《项目架构那点儿事》——浅析web层struts2的构建
【前言】所谓快速开发,实质上为了节省项目的开支成本,减少程序员的开发时 间,固然就形成了种种二次封装的框架,也就是造轮子,然后我们的程序就按照这个轮子去画瓢,这里我就把公司这几次开发系统的框架源码贴出来,做一下讲解以 及使用示范,并有附件提供参考,希望能给各位在基于后台管理系统提供帮助。
【目录】
1.struts2的配置
2.struts2的基类构成
3.具体实例应用
【内容】
一、struts2的配置
1 .struts2的过滤器拦截配置 :相信大家对struts2的配置一定不陌生,这里我就简单带过struts2过滤器在web.xml的配置:
- <filter>
- <filter-name>struts2</filter-name>
- <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>struts2</filter-name>
- <url-pattern>*.action</url-pattern>
- </filter-mapping>
A.基于Annotation的配置(struts2有一种叫convention的插件,可以实现零配置,具体可以百度Struts2 convention,我就不做讲解,注:这里的零配置是针对struts2在xml中配置)。
B.采用通配符进行配置,也就是我推荐的,也是我们项目中用到的一种方法,先上代码struts.xml:
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE struts PUBLIC
- "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
- "http://struts.apache.org/dtds/struts-2.0.dtd">
- <struts>
- <package name="default" namespace="/" extends="struts-default">
- <global-results>
- <result name="error">/page/error.jsp</result>(1)
- <result name="input"></result>(1)
- <result name="login" type="redirect">/login.jsp</result>(1)
- <result>${target}</result>(2)
- <result type="redirectAction" name="redirectAction">${target}</result>(2)
- <result type="redirect" name="redirect">${target}</result>(2)
- </global-results>
- </package>
- <package name="app" namespace="/" extends="default">(4)
- <action name="*/*/*" class="st.{1}.web.{2}Action" method="{3}">(3)
- </action>
- </package>
- </struts>
解 析:上面我对配置文件中加入(1)、(2)、(3)、(4),表示对此处的标注,下面我就对这些部分进行解析。 (1):如果有用过struts2的童鞋,可以清晰的看出它们名称都很有含义,对没错 struts2的Action类已经封装这4个静态常量,当我们在Action的方法中完成操作后,要对视图进行 跳转或者响应时,要返回一个字符串,比如:return SUCCESS;那么这个SUCCESS实际上就是对应我们在struts2配置的xxxx.jsp,简化一下也就是xxx.jsp,默认的result name就是"success" 默认的type是dispatch 也就是JSP视图,那么这样我们就可以对这些预定好的变量配置他们响应的跳转视图页面。
(2)
:很奇怪为什么有个${target},${target}只是作为struts2的配置的占位参数,而基类BaseAction中我们存放了一个
target变量,当解析struts.xml时,可以从我们实现类中读
取出来,然后进行替换,这样做的好处是什么,很显然,我们要返回的jsp页面有成千上万种,我不可能每次都去配置 a.jsp
b.jsp....,这样可以说是实现了统一设置路径,也就是通配,而且还有不同类型的返回,type="redirect"/
type="redirectAction",看上去好像是一样的,区别在于redirectAction可以指定重定向到某个action上
(struts2中配置的action),target就是Action的name,值得注意的是我这里只是罗列了重定向以及Jsp视图的类型,要知道还
有其他N多种类型的视图,怎么办?我先把关于模板类型的返回的告知出来以freemaker为例,其他见基类BaseAction:
struts.xml 中加入freemaker" name="freemaker">${target} ,其实道理是一样 只是type不一样而已,target="xxxx.ftl";
(3):这个是很重要的,我们所有的action都用了通用,原则是:{模块名}/{用例名}/{方法}.action
比如:st.sys.web.UserAction.java - sttbas_server/src/java这样一个类,我们访问它的查询方法:sys/User/view.action,很简单。
(4):我们这个名为app的package继承了 default包,也就意味可以重用default的配置。
好
像struts.xml少了点什么东西,对我们没有配置它的属性,这里我们将struts2的属性配置进行区分,也是官方推荐的设置将
struts.xml,与struts.properties分开,并放入classpath目录下,struts.properties内容如下:
#允许使用下划线#struts.enable.SlashesInActionNames=true //必须要的,因为我们配置Action时用了下划线#spring做为对象管理工厂#struts.objectFactory=spring#开发模式#struts.devMode=false//开发阶段可以开启这个模式#静态缓存#struts.serve.static.browserCache=false //开发阶段可以开启#配置是否重新加载#struts.configuration.xml.reload=true //建议开启,方便调试,发布版本的时候可以关闭
当然还有很多属性的配置,详细可以参考struts2源码包中struts.properties
二、struts2的基类
- package com.st.web.action;
- import java.io.IOException;
- import java.util.Map;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.servlet.http.HttpSession;
- import org.apache.commons.lang.StringUtils;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.apache.struts2.ServletActionContext;
- import org.apache.struts2.interceptor.ServletRequestAware;
- import org.apache.struts2.interceptor.ServletResponseAware;
- import org.apache.struts2.interceptor.SessionAware;
- import com.opensymphony.xwork2.ActionContext;
- import com.opensymphony.xwork2.ActionSupport;
- import com.opensymphony.xwork2.ModelDriven;
- import com.opensymphony.xwork2.Preparable;
- import com.st.utils.AjaxMsg;
- import com.st.utils.JsonUtil;
- /**
- * @author fisher
- * @description Action公共基类
- * @param 所有对象类型
- */
- public abstract class BaseAction extends ActionSupport implements
- ModelDriven, Preparable, SessionAware, ServletRequestAware,
- ServletResponseAware {
- private static final long serialVersionUID = 1L;
- protected Log log = LogFactory.getLog(getClass());
- // -- header 常量定义 --//
- private static final String HEADER_ENCODING = "encoding";
- private static final String HEADER_NOCACHE = "no-cache";
- private static final String DEFAULT_ENCODING = "UTF-8";
- private static final boolean DEFAULT_NOCACHE = true;
- // -- Content Type 定义 --//
- public static final String TEXT_TYPE = "text/plain";
- public static final String JSON_TYPE = "application/json";
- public static final String XML_TYPE = "text/xml";
- public static final String HTML_TYPE = "text/html";
- public static final String JS_TYPE = "text/javascript";
- public static final String EXCEL_TYPE = "application/vnd.ms-excel";
- public static final String IMG_TYPE = "image/jpeg";
- // -------------------- 作用域对象 --------------------//
- /** sessionMap对象 */
- private Map sessionMap;
- /** request对象 */
- private HttpServletRequest request;
- /** response对象 */
- private HttpServletResponse response;
- /** ajax消息 */
- public static final AjaxMsg ajaxMsg = new AjaxMsg();
- // --------------------视图跳转路径------------------//
- /**
- * 例如:"index.jsp index.ftl"
- */
- private String target;
- // -- Preparable函数 --//
- /**
- * 实现空的prepare()函数,屏蔽了所有Action函数都会执行的公共的二次绑定.
- */
- public void prepare() throws Exception {
- }
- // -------------绕过jsp/freemaker直接输出文本函数-------------//
- // -- 绕过jsp/freemaker直接输出文本的函数 --//
- /**
- * 直接输出内容的简便函数. eg. render("text/plain", "hello", "encoding:GBK");
- * render("text/plain",hello", "no-cache:false");
- * render("text/plain","hello", "encoding:GBK","no-cache:false");
- *
- * @param headers
- * 可变的header数组,目前接受的值为"encoding:"或"no-cache:",默认值分别为UTF-8和true.
- */
- public static void render(final String contentType, final String content,
- final String... headers) {
- HttpServletResponse response = initResponseHeader(contentType, headers);
- try {
- response.getWriter().write(content);
- response.getWriter().flush();
- } catch (IOException e) {
- throw new RuntimeException(e.getMessage(), e);
- }
- }
- public static void renderImg(final String img, final String... headers) {
- render(IMG_TYPE, img, headers);
- }
- /**
- * 直接输出文本.
- *
- * @see #render(String, String, String...)
- */
- public static void renderText(final String text, final String... headers) {
- render(TEXT_TYPE, text, headers);
- }
- /**
- * 直接输出HTML.
- *
- * @see #render(String, String, String...)
- */
- public static void renderHtml(final String html, final String... headers) {
- render(HTML_TYPE, html, headers);
- }
- /**
- * 直接输出XML.
- *
- * @see #render(String, String, String...)
- */
- public static void renderXml(final String xml, final String... headers) {
- render(XML_TYPE, xml, headers);
- }
- /**
- * 直接输出JSON.
- *
- * @param jsonString
- * json字符串.
- * @see #render(String, String, String...)
- */
- public static void renderJson(final String jsonString,
- final String... headers) {
- render(JSON_TYPE, jsonString, headers);
- }
- /**
- * 直接输出JSON,使用fastJson转换Java对象.
- *
- * @param data
- * 可以是List, POJO[], POJO, 也可以Map名值对.
- * @see #render(String, String, String...)
- */
- public static void renderJson(final Object data, final String... headers) {
- String jsonString = JsonUtil.serialize(data);
- renderJson(jsonString, headers);
- }
- public static void renderJson(final Object data,
- final String[] propertyFilter, final boolean isInclude,
- final String... headers) {
- String jsonString = JsonUtil.serialize(data, propertyFilter, isInclude);
- renderJson(jsonString, headers);
- }
- /**
- * 分析并设置contentType与headers.
- */
- private static HttpServletResponse initResponseHeader(
- final String contentType, final String... headers) {
- // 分析headers参数
- String encoding = DEFAULT_ENCODING;
- boolean noCache = DEFAULT_NOCACHE;
- for (String header : headers) {
- String headerName = StringUtils.substringBefore(header, ":");
- String headerValue = StringUtils.substringAfter(header, ":");
- if (StringUtils.equalsIgnoreCase(headerName, HEADER_ENCODING)) {
- encoding = headerValue;
- } else if (StringUtils.equalsIgnoreCase(headerName, HEADER_NOCACHE)) {
- noCache = Boolean.parseBoolean(headerValue);
- } else {
- throw new IllegalArgumentException(headerName
- + "不是一个合法的header类型");
- }
- }
- HttpServletResponse response = ServletActionContext.getResponse();
- // 设置headers参数
- String fullContentType = contentType + ";charset=" + encoding;
- response.setContentType(fullContentType);
- if (noCache) {
- // Http 1.0 header
- response.setDateHeader("Expires", 1L);
- response.addHeader("Pragma", "no-cache");
- // Http 1.1 header
- response.setHeader("Cache-Control", "no-cache, no-store, max-age=0");
- }
- return response;
- }
- /**
- * @description 获取磁盘物理路径
- * @return String
- */
- protected String getRealPath() {
- return request.getSession().getServletContext().getRealPath("");
- }
- /**
- * @description 得到session对象
- * @return Session
- */
- protected HttpSession getSession() {
- return this.request.getSession();
- }
- /**
- * @Title: getParams
- * @Description: 得到页面所有参数
- * @return Map
- * @throws
- */
- public Map getParameters() {
- return ActionContext.getContext().getParameters();
- }
- /**
- * @description 设置session对象Attribute属性
- * @param key
- * @param value
- */
- protected void setSessionAttribute(String key, Object value) {
- sessionMap.put(key, value);
- }
- /**
- * @description 返回session对象的Attribute属性
- * @param key
- * @return Object
- */
- protected Object getSessionAttribute(String key) {
- return sessionMap.get(key);
- }
- /**
- * @description 清除整个session
- */
- protected void clearSession() {
- sessionMap.clear();
- }
- /**
- * @description 清除session中指定的内容
- * @param key
- */
- protected void remove(Object key) {
- sessionMap.remove(key);
- }
- /**
- * @description 通过request获取页面参数值
- * @return string
- */
- protected String getParameters(String name) {
- return (null != request.getParameter(name)) ? request
- .getParameter(name) : null;
- }
- /**
- * @description 获取项目根目录
- * @return String
- */
- protected String getRootPath() {
- return request.getContextPath();
- }
- /**
- * @description 获取request独享
- * @return
- */
- public HttpServletRequest getRequest() {
- return request;
- }
- /**
- * @description 获取response对象
- * @return
- */
- public HttpServletResponse getResponse() {
- return response;
- }
- /**
- * @description 获取sessionMap
- * @return
- */
- public Map getSessionMap() {
- return sessionMap;
- }
- public String getTarget() {
- return target;
- }
- public void setTarget(String target) {
- this.target = target;
- }
- public void setServletResponse(HttpServletResponse response) {
- this.response = response;
- }
- public void setServletRequest(HttpServletRequest request) {
- this.request = request;
- }
- public void setSession(Map sessionMap) {
- this.sessionMap = sessionMap;
- }
- }
解析:
1.
接到上面struts2的配置问题来说,可以看到我们在配置result的时候存在占位参数${target},那这个target是哪里来的?可以看
到,BaseAction中已经包含这个变量,并且提供get方法,有童鞋会问为什么这样子对target设置就能替换${target},我只能说这是
OGNL的一种机制。
2.可以看出baseAciton中定义了很多常量,怎么用?这些常量定义是为了处理response
的响应头,上面我有讲过,我没有在struts.xml中处理流返回类型,json返回类型,对吧?很显然是要在这里做操作了撒,可以看出有很多
render开头的重载方法,这些方法就是帮助我们直接去响应前台,后面例子中我会附带系统中struts2对json处理、对流文件(excel、
img)处理。
3.实现了很多接口,值得注意的是Preparable和ModelDriven。注意这个BaseAction是泛型,就是因为ModelDriven(模型驱动),有了它我们可以直接由ModelDriven的interceptor拦截前台参数,把参数分装成我们指定的泛型类型的对象,而Preparable则是提供给一个预处理接口,让在执行Action方法之前执行。其他几个几口是帮助我们获取作用域对象,session、request。
4.附件中会包含基类的引用类,JsonUtil(json工具类)以及AjaxMsg(ajax消息类,针对Json消息)
三、具体示例
示例我写得很简单,大概就是举例一下,如何进行前后台的交互,以及响应不同返回类型。由于帖子长度有限,所以基类的代码何示例代码大家只有下载了,写这篇文章耗费了我3个小时,由于文笔水品有限,有瑕疵的地方,请大家指正批评。
四、附件地址
http://pan.baidu.com/share/link?shareid=2838805807&uk=2701872319
《项目架构那点儿事》——浅析web层struts2的构建的更多相关文章
- 《项目架构那点儿事》——Hibernate泛型Dao,让持久层简洁起来
[前言]hibernate作为持久层ORM技术,它对JDBC进行非常轻量级对象封装,使得我们可以随心所欲的使用面向对象的思想来操作数据 库.同时,作为后台开发的支撑,的确扮演了一个举足轻重的角色,那么 ...
- 《项目架构那点儿事》——快速构建Junit用例
[前 言]按照惯例,在实际项目中我往往会对自己编写的程序进行测试,当测试通过后才能将其用于实战中,当然,编写单元测试是不可避免的,可以直接清晰的检验出 我们程序的可靠性.可只执行性,从中发现问题从而得 ...
- IDEA项目搭建二——使用SpringBoot创建Web层
一.编写底层代码 1.demo-common中创建FormatString类 先在默认com.tyh中创建package命名为common 删除自动生成的app.java,在common包下创建新类 ...
- .net大型平台通过Nginx做负载均衡(Web层、中间服务层、DB层)
.net平台下,我目前部署过的均衡负载有两种方式(iis7和Nginx),以下以Nginx为例讲解web层的均衡负载. 简介:Nginx 超越 Apache 的高性能和稳定性,使得国内使用 Nginx ...
- [译]ABP框架使用AngularJs,ASP.NET MVC,Web API和EntityFramework构建N层架构的SPA应用程序
本文转自:http://www.skcode.cn/archives/281 本文演示ABP框架如何使用AngularJs,ASP.NET MVC,Web API 和EntityFramework构建 ...
- mvc项目架构搭建之UI层的搭建
项目架构搭建之UI层的搭建 Contents 系列一[架构概览] 0.项目简介 1.项目解决方案分层方案 2.所用到的技术 3.项目引用关系 系列二[架构搭建初步] 4.项目架构各部分解析 5.项目创 ...
- 项目架构开发:数据访问层之Cache
数据访问层简单介绍 数据访问层,提供整个项目的数据访问与持久化功能.在分层系统中所有有关数据访问.检索.持久化的任务,最终都将在这一层完成. 来看一个比较经典的数据访问层结构图 大概可以看出如下信息 ...
- Web应用程序系统的多用户权限控制设计及实现-项目架构【3】
本章主要讲述Web权限管理系统的项目架构,及开发中需要的基本类和相关的CSS,JS文件. 1.1系统结构 本系统搭建开发工具为Visual Studio 2012,采用ASP.NET MVC 4.0技 ...
- 项目架构开发:数据访问层之Logger
接上文 项目架构开发:数据访问层之Cache 本章我们继续ILogger的开发 ILogger.cs public interface ILogger { void Info(object messa ...
随机推荐
- 最常用前端框架BootStrap——栅格系统
前 言 Bootstrap 提供了一套响应式.移动设备优先的流式栅格系统,随着屏幕或视口(viewport)尺寸的增加,系统会自动分为最多12列.它包含了易于使用的预定义类,还有强大的mix ...
- 关于Android SDK Manager无法获取更新列表的正确设置
1.以"管理员身份运行"SDK Manager. 2.Android SDK Manager"=>"Tools"=>"Optio ...
- commons-pool与commons-pool2连接池(Hadoop连接池)
commons-pool和commons-pool2是用来建立对象池的框架,提供了一些将对象池化必须要实现的接口和一些默认动作.对象池化之后可以通过pool的概念去管理其生命周期,例如对象的创建,使用 ...
- JavaScript命令模式
第一,命令模式: (1)用于消除调用者和接收者之间直接的耦合的模式,并且可以对(调用这个过程进行留痕操作) (2)真的不要乱用这个模式,以为他使你简单调用写法变得非常的复杂和有些难以理解. (3)你的 ...
- JPA + SpringData 操作数据库原来可以这么简单 ---- 深入了解 JPA - 1
原创播客,如需转载请注明出处.原文地址:http://www.cnblogs.com/crawl/p/7703679.html ------------------------------------ ...
- gevent的同步与异步
from gevent import spawn,joinall,monkey;monkey.patch_all() import time def task(pid): time.sleep(0.5 ...
- Oracle学习笔记之游标详解
游标 游标存在意义:解决"select *"返回空.多行记录问题,但凡select,就可能多行结果集,也就需要用游标. 游标分4步走:cursor.open.fetch.close ...
- 【持续更新】.Net 开发中给自己埋下的坑!
1.文件“XXX”正在由另一进程使用,因此该进程无法访问此文件. 原因剖析:文件在主线程操作,在子线程中读写操作文件,刚开始没有意识到程序的问题所在,总是在FileStream中报错,google后常 ...
- Linux系列教程(四)——Linux文件和目录处理命令
这个系列教程的前面我们讲解了如何安装Linux系统,以及学习Linux系统的一些方法.那么从这篇博客开始,我们就正式进入Linux命令的学习.学习命令,首先要跟大家纠正的一点就是,我们不需要记住每一条 ...
- Javascript里的if判断与逻辑运算符(||, &&)和比较运算符的特别之处
写JS时不可避免要用到 if 与 逻辑运算符( ||, &&). 如果你经常阅读Js的第三方组件源码, 会发现有一种写法作为初始化变量的方法经常出现. var variable = v ...