Struts2通过拦截器反射批量获取参数
来源:互联网 发布:js 过滤空格 和换行符 编辑:程序博客网 时间:2024/05/20 11:19
Struts2通过拦截器反射批量获取参数
之前用struts2弄一个erp项目,里面的表单字段数比较多。刚刚开始的时候耐心的一个一个去从request中拿,后来实在是受不了这种体力劳动了,遂上网寻找解决方案。总结起来,目前市面上比较常用的struts2批量获取参数的方法主要有以下几种。
1:通过添加action的属性设置get和set获取。
这种方法是最常见的,确实挺高效,但我一直不愿意用。主要是感觉这种方法会导致整个action代码十分混乱,它们应该被集中起来放到一个对象(view object)中才对。并且通过这种方式,我们不能自己去控制它的默认值,得去深入了解struts2的脾气。2:在action中设置一个对象获取。
确实,action中可以构建一个对象,然后把属性塞到这个对象里,struts2框架会帮你把前端传递过来的数据填充进去。但最让人郁闷的是,页面变量名的书写格式必须是【对象名.属性名】。Oh,shit!为什么要弄这种耦合呢,本来页面就是要尽量的与后台分离,你总不能让前端写页面的时候先问下你打算用哪个类名吧。完全不理解struts2的作者,都到这一步了还急着去打dota,难道说是有什么别的目的,这个我就不懂了,有高人可以指点下。
3: ModelDriven接口
Struts2有一个ModelDriven接口。使用实例如下:
public class YouAction extends ActionSupport implements ModelDriven<YourBean> { private YourBean sheep = new YourBean; public YourBean getSheep() { return sheep; } public void setSheep(YourBean sheep) { this.sheep = sheep; } public String execute() throws Exception { return SUCCESS; } @override public YourBean getModel(){ return sheep; }}
为什么需要在两个地方指定bean呢,弄成一个的不行么?或者,完全不需要指定的不行么?其实我没用的原因主要是我没调试成功~~!不知道是不是我的bean继承了太多层还是我的action继承了太多层,总之我这样写,数据没给我放好,还请高手指点。话说这种叫模型驱动,方法1叫属性驱动,诶,不懂不懂……
在失望和绝望过后,我按照自己的设想,写了一套解决方案。
大概来说,就是用拦截器+反射把request的提交参数自动映射到我定义好的vo对象里(其实struts2也是这么干的),然后把参数验证也放到拦截器中去实现,这样每个action我只要提供返回boolean类型的验证函数就可以了。
AbstractVO.java,所有的vo对象(或者叫form、dto)都继承该类
import java.util.ArrayList;import java.util.List;//view objectpublic abstract class AbstractVO { //get请求验证public boolean validGet(){return true;} //post请求验证public boolean validPost(){return true;} //get请求验证失败时的回调函数public void validGetFailRockback(){} //post请求验证失败时的回调函数public void validPostFailRockback(){} //验证消息存放列表,可以在验证失败时把原因传递出去private List<String> validMsg = new ArrayList<String>();public void addMsg(String msg){this.validMsg.add(msg);}public List<String> allMsg(){return this.validMsg;}//检查非空,这是常用的验证public boolean checkBlank(String...strings){for(String s:strings){if(s == null || s.equals("")){this.addMsg("某些数据不能为空");return false;}}return true;} //其他通用的验证可以往下扩展}
DemoAction.java下面是action类
import java.util.Date;import com.opensymphony.xwork2.ActionSupport;public class DemoAction extends ActionSupport{private InnerForm form = new InnerForm();//必须先进行实例化 public InnerForm getForm() {//必须有get方法,拦截器需要,失败返回INPUT后页面状态保留也需要 return form; } @Overridepublic String execute() throws Exception {if(isGet()){ // 这里,你可以专注做你自己的事情了,数据获取和验证都已经在拦截器里帮你处理 // 你要做的就是从form对象里获取你自己需要的东西,可以使用apache的commos-BeabUtils帮你实现快速的bean属性转移,把form里面的东西分发给不同的model对象 return INPUT;}if(isPost()){ // 如上 return SUCCESS;}return ERROR;} // 该form和该action是紧密相关的,可以定义为内部类,但要注意使用public修饰,这样失败才能通过get方法回传给前端public class InnerForm extends AbstractVO { private String name; private int age;@Overridepublic boolean validPost() { boolean rt = true;rt = super.checkBlank(name);//调用公用的非空验证 if(age < 0 || age > 100){//一些个性化验证 super.addMsg("年龄范围不对"); rt = false; } return rt;} public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }}
ParamInterceptor.java最关键的拦截器全部代码
import java.lang.reflect.Method;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date;import java.util.List;import javax.servlet.http.HttpServletRequest;import org.apache.struts2.StrutsStatics;import com.opensymphony.xwork2.Action;import com.opensymphony.xwork2.ActionSupport;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionInvocation;import com.opensymphony.xwork2.interceptor.AbstractInterceptor;public class ParamInterceptor extends AbstractInterceptor {@Overridepublic String intercept(ActionInvocation invocation) throws Exception {ActionContext actionContext = invocation.getInvocationContext(); HttpServletRequest request = (HttpServletRequest) actionContext.get(StrutsStatics.HTTP_REQUEST); ActionSupport action = (ActionSupport)invocation.getAction();String requestMethod = request.getMethod().toUpperCase(); Method[] methods = action.getClass().getMethods();//获取action的所有public方法 for(Method method:methods){ if(method.getName().startsWith("get")){//遍历action对象的get方法 if(AbstractVO.class.equals(method.getReturnType().getSuperclass())){//如果方法的返回类型是AbstractVO的直接子类(不支持多次继承,高手帮改进下) Object vo = null; try{ vo = method.invoke(action, new Object[]{});//调用该方法希望能获取AbstractVO子类实例,这里要求action里定义的AbstractVO子类已经被实例化 }catch(Exception o){} if(vo instanceof AbstractVO){//确保vo对象不为null并且是AbstractVO类型子类 Method[] voMethods = vo.getClass().getMethods(); for(Method voMethod:voMethods){ if(voMethod.getName().startsWith("set")){//遍历vo对象的set方法 Type[] methodParams = voMethod.getParameterTypes(); Type[] methodGenericParams = voMethod.getGenericParameterTypes(); String attributeName = voMethod.getName().substring(3, 4).toLowerCase() + voMethod.getName().substring(4, voMethod.getName().length()); if(methodParams.length == 1){//如果set方法的参数个数是1 Object defValue = null; boolean defLock = false; String[] oValues = request.getParameterMap().get(attributeName); //下面开始设置给vo对象填充数据,应该有更简单的书写方式 try{ if(methodParams[0].equals(Integer.TYPE)){//如果set方法的参数类型是Integer或int类型 defValue = -1;//失败默认值 voMethod.invoke(vo, Integer.parseInt(oValues[oValues.length - 1]));//取最后一个参数,当get参数和post参数重名时优先使用post的参数 }else if(methodParams[0].equals(String.class)){//如果set方法的参数类型是String类型 defValue = "";//失败默认值 voMethod.invoke(vo, oValues[oValues.length - 1]); }else if(methodParams[0].equals(Long.TYPE)){//如果set方法的参数类型是long类型,可以用long类型保存价格,以和int类型分开(不懂还有没有别的解决方案,比如int类型是否可以定义别名) //目的:把价格转化成分为单位的整数,比如12就是1200,12.3就是1230,12.03就是1203 defValue = -1l;//失败默认值 String source = oValues[oValues.length - 1]; String[] arr = source.split("."); //……偷懒了 Long mylong = 1l; voMethod.invoke(vo, mylong]); }else if(methodParams[0].equals(Date.class)){ }else if(methodParams[0].equals(Boolean.TYPE)){ }else if(methodParams[0].equals(List.class)){//如果set方法的参数类型是List类型 Type rawType = ((ParameterizedType)methodGenericParams[0]).getActualTypeArguments()[0]; if(rawType.equals(Integer.TYPE)){//如果List的泛型类型是Integer或int类型 List<Integer> rs = new ArrayList<Integer>(); defValue = rs; for(String val:oValues){ rs.add(Integer.parseInt(val)); } voMethod.invoke(vo, rs); }else if(rawType.equals(String.class)){ }else if(rawType.equals(Date.class)){ }else if(rawType.equals(Boolean.TYPE)){ }else{} //如果是array对象暂时还不懂怎么处理,高手帮忙 }else{ defLock = true; } }catch(Exception e){ if(!defLock){ try{ voMethod.invoke(vo, defValue);//尝试使用默认值 }catch(Exception s){ } } } } } } //参数验证 boolean rt = true; AbstractVO instance = ((AbstractVO)vo); if(requestMethod.equals("GET")){ rt = instance.validGet(); if(!rt){ instance.validGetFailRockback();//失败回调 } } if(requestMethod.equals("POST")){ rt = instance.validPost(); if(!rt){ instance.validPostFailRockback();//失败回调 } } if(!rt){ for(String msg:instance.allMsg()){ //如果验证失败了,这里可以处理失败消息,一般是放到session里传递给前端展示 } return Action.INPUT; } } } } }return invocation.invoke();}}
Struts.xml,拦截器的配置还是得给些新手说说的,关键代码如下
<interceptors> <interceptor name="json" class="org.apache.struts2.json.JSONInterceptor"/> <interceptor name="context" class="com.sheep.ContextInterceptor"/> <interceptor name="paramInit" class="com.sheep.ParamInterceptor"/> <interceptor-stack name="basicStack"> <interceptor-ref name="basicStack"/> <interceptor-ref name="staticParams"/> <interceptor-ref name="context"/> <interceptor-ref name="paramInit"/> </interceptor-stack> </interceptors> <default-interceptor-ref name="basicStack"/>
另一个拦截器ContextInterceptor是做系统登录验证和权限验证什么用的,放它后面就行。
发现控制层还是spring的思想比较优秀啊。
- Struts2通过拦截器反射批量获取参数
- struts2通过拦截器后配置文件如何获取参数值
- struts2拦截器获取http请求参数
- Struts2拦截器获取session
- 通过反射获取泛型参数类型
- java通过反射获取泛型参数
- Struts2+Spring+AOP 权限拦截+反射获取Action权限注解
- 通过struts2拦截器实现权限管理
- struts2 Interceptor(拦截器)中获取HTTP 参数的方法
- 在Struts2拦截器中获取请求action名称及参数
- 在Struts2拦截器中获取请求action名称及参数
- struts2 拦截器 请求参数 更改
- 使用参数拦截器通过注解直接从JSON对象中获取数据
- J2EE,struts2 拦截器中获取 server
- struts2拦截器获取请求相关内容
- Struts2(二)-Struts2之参数绑定和拦截器
- 黑马程序员-通过反射获取泛型参数类型
- java 通过反射获取方法参数列表名称
- 使用一个手指旋转UIView的代码
- error :does not name a type
- ListBox 显示最后一项
- Android: Android Touch事件处理
- 产品设计 - 整体一致性
- Struts2通过拦截器反射批量获取参数
- Cocos2d中遇到的问题
- 字符串反转的几种方法
- Android之PopupWindow弹出对话框
- Status Code Definitions-http状态码
- 《OpenGL编程基础》第三章笔记2
- 数据挖掘流程
- R.java was modified manually! Reverting to generated version!
- 性能测试如何定位瓶颈