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 object
public 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;
}
@Override
public 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;
@Override
public 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 {
@Override
public 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拦截器(Interceptor) Struts2拦截器(Interceptor)
解决Struts2中的中文乱码。该代码是用作Struts2的拦截器中
该例子为struts2注解与拦截器demo,利用myEclipse8.5开发,导入刚才后,自动加载所需struts2的jar包,可以直接运行,是初学struts2注解、拦截器很好的例子,保证10分钟学会2种技术,愿意分享给大家。
struts2常用拦截器,struts2经常用到的拦截器,熟悉熟悉
struts2 Interceptor拦截器 http://whitewolf.0fees.net
使用Struts2实现用户权限拦截、重点是掌握拦截器的使用和配置方法,通过案例的学习,就能掌握struts中拦截器的使用方法,让我们能快速上手
Struts2拦截器.ppt Struts2拦截器.ppt Struts2拦截器.ppt
关于struts2 拦截器的详细的解释及其在开发中对struts2的拦截器的应用和拦截器在框架中的作用.
Struts2拦截器源程序 Struts2拦截器源程序 Struts2拦截器源程序 Struts2拦截器源程序 Struts2拦截器源程序
详细说明了struts2中拦截器的使用。并且通过一个小例子讲解了拦截器的具体使用
struts2,Interceptor struts2拦截器实例,两套实例,一套是针对单个的action配置的,另一套实例是针对全局的action配置的拦截器interceptor
基于struts2的拦截器测试,实现了页面的跳转,中间过程的拦截
struts2拦截器应用小例子,与大家共分享
struts2 用拦截器 实现用户权限登录 可以直接运行,只单单用到struts的东西。
Struts2拦截器实现权限控制demo,我感觉对初学者还是有一定帮助的
Struts2的核心,拦截器的应用!!!
Struts2的拦截器的使用详解实例 博文链接:https://zmx.iteye.com/blog/457434
struts2内置拦截器简介 basic default
综合使用servlet filter与struts2 interceptor对权限进行验证。
Struts2内建拦截器的简要介绍,Struts2内建拦截器的简要介绍,Struts2内建拦截器的简要介绍