Struts2 和 Spring MVC 孰优孰劣

简介:

最近我在将APDPlat升级到Java8,由于之前有很多的同学希望我把APDPlat的struts2替换为spring mvc,所以我就决定试试看。

本次我把APDPlat的struts2改造为spring mvc的目标是:99.99%不改动JS、HTML、JSP等前端代码,只改JAVA代码!所以大家要先理解我的目标,然后再来看我的做法。

本文我们看两个转换前后的例子:

1、下拉列表服务,此类比较简单,只涉及一个方法store:

使用struts2:

@Scope("prototype")
@Controller
@Namespace("/dictionary")
public class DicAction extends ExtJSSimpleAction<Dic> {
    @Resource
    private DicService dicService;
    private String dic;
    private String tree;
    private boolean justCode;
    
    /**
     * 
     * 此类用来提供下拉列表服务,主要有两种下列类型:
     * 1、普通下拉选项
     * 2、树形下拉选项
     * @return 不需要返回值,直接给客户端写数据
     * 
     */
    public String store(){
        Dic dictionary=dicService.getDic(dic);
        if(dictionary==null){
            LOG.info("没有找到数据词典 "+dic);
            return null;
        }
        if("true".equals(tree)){
            String json = dicService.toStoreJson(dictionary);
            Struts2Utils.renderJson(json);
        }else{
            List<Map<String,String>> data=new ArrayList<>();
            for(DicItem item : dictionary.getDicItems()){
                Map<String,String> map=new HashMap<>();
                if(justCode){
                    map.put("value", item.getCode());
                }else{
                    map.put("value", item.getId().toString());
                }
                map.put("text", item.getName());
                data.add(map);
            }
            Struts2Utils.renderJson(data);
        }
        return null;
    }

    publ
i```  
c void setJustCode(boolean justCode) {
        this.justCode = justCode;
    }

    public void setTree(String tree) {
        this.tree = tree;
    }

    public void setDic(String dic) {
        this.dic = dic;
    }
}
使用spring mvc:

@Scope("prototype")
@Controller
@RequestMapping("/dictionary")
public class DicAction extends ExtJSSimpleAction {

@Resource
private DicService dicService;

/**
 * 
 * 此类用来提供下拉列表服务,主要有两种下拉类型:
 * 1、普通下拉选项
 * 2、树形下拉选项
 * @param dic
 * @param tree
 * @param justCode
 * @return 返回值直接给客户端
 */
@ResponseBody
@RequestMapping("/dic!store.action")
public String store(@RequestParam(required=false) String dic,
                    @RequestParam(required=false) String tree,
                    @RequestParam(required=false) String justCode){
    Dic dictionary=dicService.getDic(dic);
    if(dictionary==null){
        LOG.info("没有找到数据词典 "+dic);
        return "";
    }
    if("true".equals(tree)){
        String json = dicService.toStoreJson(dictionary);
        return json;
    }else{
        List<Map<String,String>> data=new ArrayList<>();
        dictionary.getDicItems().forEach(item -> {
            Map<String,String> itemMap=new HashMap<>();
            if("true".equals(justCode)){
                itemMap.put("value", item.getCode());
            }else{
                itemMap.put("value", item.getId().toString());
            }
            itemMap.put("text", item.getName());
            data.add(itemMap);
        });
        String json = JSONArray.fromObject(data).toString();
        return json;
    }
}

}


从上面我们可以看到,struts2和spring mvc的区别非常明显,struts2使用原型,spring mvc使用单例。

单例一定比原型快吗?创建一个对象的开销可以忽略吗?这个问题需要在自己的场景中考虑,不过大多时候我们是可以忽略的。

APDPlat之前使用struts2,每一个请求都会对应一个全新的Action,所以请求的参数就可以作为Action的字段来自动注入,言下之意就是Action中的所有方法都可以共用字段,而现在换成spring mvc了,不同的方法需要各自获取请求中的参数。

对比以上代码,我个人还是认为spring mvc的方式更好一些,对于Action(spring mvc叫Controller)来说,单例、无状态是比较理想的。



2、数据字典服务,此类比较复杂,涉及的方法有create、delete、updatePart、retrieve、query、store:

使用struts2:

@Scope("prototype")
@Controller
@Namespace("/dictionary")
public class DicItemAction extends ExtJSSimpleAction {

@Resource
private DicService dicService;
private String node;

/**
 * 返回数据字典目录树
 * @return 
 */
public String store() {
    if (node == null) {
        return null;
    }
    Dic dic=null;
    if(node.trim().startsWith("root")){
        dic = dicService.getRootDic();
    }else{
        int id=Integer.parseInt(node);
        dic = dicService.getDic(id);
    }
    
    if (dic != null) {
        String json = dicService.toJson(dic);
        Struts2Utils.renderJson(json);
    }
    return null;
}

public void setNode(String node) {
    this.node = node;
}

}

使用spring mvc:

@Scope("prototype")
@Controller
@RequestMapping("/dictionary")
public class DicItemAction extends ExtJSSimpleAction {

@Resource
private DicService dicService;

/**
 * 返回数据字典目录树
 * @param node
 * @return 
 */
@ResponseBody
@RequestMapping("/dic-item!store.action")
public String store(@RequestParam(required=false) String node) {
    if (node == null) {
        return "[]";
    }
    Dic dic=null;
    if(node.trim().startsWith("root")){
        dic = dicService.getRootDic();
    }else{
        int id=Integer.parseInt(node);
        dic = dicService.getDic(id);
    }
    
    if (dic != null) {
        String json = dicService.toJson(dic);
        return json;
    }
    return "[]";
}
@ResponseBody
@RequestMapping("/dic-item!query.action")
public String query(@RequestParam(required=false) Integer start,
                    @RequestParam(required=false) Integer limit,
                    @RequestParam(required=false) String propertyCriteria,
                    @RequestParam(required=false) String orderCriteria,
                    @RequestParam(required=false) String queryString,
                    @RequestParam(required=false) String search){
    super.setStart(start);
    super.setLimit(limit);
    super.setPropertyCriteria(propertyCriteria);
    super.setOrderCriteria(orderCriteria);
    super.setQueryString(queryString);
    super.setSearch("true".equals(search));
    return super.query();
}
@ResponseBody
@RequestMapping("/dic-item!retrieve.action")
public String retrieve(@ModelAttribute DicItem model) {
    super.model = model;
    return super.retrieve();
}
@ResponseBody
@RequestMapping("/dic-item!delete.action")
public String delete(@RequestParam String ids) {
    super.setIds(ids);
    return super.delete();
}
@ResponseBody
@RequestMapping("/dic-item!create.action")
public String create(@ModelAttribute DicItem model) {
    super.model = model;
    return super.create();
}
@ResponseBody
@RequestMapping("/dic-item!updatePart.action")
public String updatePart(@ModelAttribute DicItem model) {
    super.model = model;
    return super.updatePart();
}

}


从上面可以看到,从struts2转换为spring mvc之后,代码一下子就增加了,父类的create、delete、updatePart、retrieve、query这5个方法对于spring mvc就无效了,而且模型注入的方式也不起作用了,下面我们要解决这两个问题。



要解决第一个问题,我们首先要改变struts2的URL调用方式,在struts2中,我们是这么调用Action的方法的,!后面是Action的方法名称:

http://localhost:8080/APDPlat_Web-2.6/dictionary/dic-item!query.action


如果我们不改变调用方式,上面刚说的那5个方法就无法抽象到父类中了,改变方式也挺简单,只需要把!改成/就可以了,在父类中增加如下代码并在前端JS中将!改成/:

@ResponseBody
@RequestMapping("query.action")
public String query(@RequestParam(required=false) Integer start,

                @RequestParam(required=false) Integer limit,
                @RequestParam(required=false) String propertyCriteria,
                @RequestParam(required=false) String orderCriteria,
                @RequestParam(required=false) String queryString,
                @RequestParam(required=false) String search){
super.setStart(start);
super.setLimit(limit);
super.setPropertyCriteria(propertyCriteria);
super.setOrderCriteria(orderCriteria);
super.setQueryString(queryString);
setSearch("true".equals(search));
return query();

}

@ResponseBody
@RequestMapping("retrieve.action")
public String retrieve(@ModelAttribute T model) {

this.model = model;
return retrieve();

}

@ResponseBody
@RequestMapping("delete.action")
public String delete(@RequestParam String ids) {

super.setIds(ids);
return delete();

}

@ResponseBody
@RequestMapping("create.action")
public String create(@ModelAttribute T model) {

this.model = model;
return create();

}

@ResponseBody
@RequestMapping("updatePart.action")
public String updatePart(@ModelAttribute T model) {

this.model = model;
return updatePart();

}


关于第二个问题,在struts2中,注入Action的参数,要使用model.id这样的方式,model是Action的一个字段,而在spring mvc中,这样是不行的,需要做一个转换,在父类中增加如下代码以使spring mvc能适应struts2参数注入方式:

/**

  • 前端向后端传递模型参数的时候都有model.前缀
  • @param binder
    */

@InitBinder
public void initBinder(WebDataBinder binder) {

binder.setFieldDefaultPrefix("model.");

}

经过上面的改进,数据字典服务 使用spring mvc的代码升级为:

@Scope("prototype")
@Controller
@RequestMapping("/dictionary/dic-item/")
public class DicItemAction extends ExtJSSimpleAction {

@Resource
private DicService dicService;

/**
 * 返回数据字典目录树
 * @param node
 * @return 
 */
@ResponseBody
@RequestMapping("store.action")
public String store(@RequestParam(required=false) String node) {
    if (node == null) {
        return "[]";
    }
    Dic dic=null;
    if(node.trim().startsWith("root")){
        dic = dicService.getRootDic();
    }else{
        int id=Integer.parseInt(node);
        dic = dicService.getDic(id);
    }
    
    if (dic != null) {
        String json = dicService.toJson(dic);
        return json;
    }
    return "[]";
}

}

文章转载自 开源中国社区 [http://www.oschina.net]
相关文章
|
1月前
|
缓存 前端开发 Java
Spring MVC 面试题及答案整理,最新面试题
Spring MVC 面试题及答案整理,最新面试题
90 0
|
1月前
ssm(Spring+Spring mvc+mybatis)——updateDept.jsp
ssm(Spring+Spring mvc+mybatis)——updateDept.jsp
10 0
|
1月前
ssm(Spring+Spring mvc+mybatis)——showDept.jsp
ssm(Spring+Spring mvc+mybatis)——showDept.jsp
9 0
|
1月前
|
SQL JavaScript Java
springboot+springm vc+mybatis实现增删改查案例!
springboot+springm vc+mybatis实现增删改查案例!
26 0
|
1月前
|
SQL Java 数据库连接
挺详细的spring+springmvc+mybatis配置整合|含源代码
挺详细的spring+springmvc+mybatis配置整合|含源代码
41 1
|
12天前
|
数据采集 前端开发 Java
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
数据塑造:Spring MVC中@ModelAttribute的高级数据预处理技巧
23 3
|
12天前
|
存储 前端开发 Java
会话锦囊:揭示Spring MVC如何巧妙使用@SessionAttributes
会话锦囊:揭示Spring MVC如何巧妙使用@SessionAttributes
14 1
|
12天前
|
前端开发 Java Spring
数据之桥:深入Spring MVC中传递数据给视图的实用指南
数据之桥:深入Spring MVC中传递数据给视图的实用指南
29 3
|
22天前
|
前端开发 安全 Java
使用Java Web框架:Spring MVC的全面指南
【4月更文挑战第3天】Spring MVC是Spring框架的一部分,用于构建高效、模块化的Web应用。它基于MVC模式,支持多种视图技术。核心概念包括DispatcherServlet(前端控制器)、HandlerMapping(请求映射)、Controller(处理请求)、ViewResolver(视图解析)和ModelAndView(模型和视图容器)。开发流程涉及配置DispatcherServlet、定义Controller、创建View、处理数据、绑定模型和异常处理。
使用Java Web框架:Spring MVC的全面指南
|
28天前
|
敏捷开发 监控 前端开发
Spring+SpringMVC+Mybatis的分布式敏捷开发系统架构
Spring+SpringMVC+Mybatis的分布式敏捷开发系统架构
65 0