struts2和spring mvc,孰优孰劣?

最近我在将APDPlat升级到Java8,因为以前有不少的同窗但愿我把APDPlat的struts2替换为spring mvc,因此我就决定试试看。前端

本次我把APDPlat的struts2改造为spring mvc的目标是:99.99%不改动JS、HTML、JSP等前端代码,只改JAVA代码!因此你们要先理解个人目标,而后再来看个人作法。java

本文咱们看两个转换先后的例子:node

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

使用struts2:github

@Scope("prototype")
@Controller
@Namespace("/dictionary")
public class DicAction extends ExtJSSimpleAction<Dic> {
    @Resource
    private DicService dicService;
    private String dic;
    private String tree;
    private boolean justCode;
    
    /**
     * 
     * 此类用来提供下拉列表服务,主要有两种下列类型:
     * 一、普通下拉选项
     * 二、树形下拉选项
     * @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;
    }

    public 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:spring

@Scope("prototype")
@Controller
@RequestMapping("/dictionary")
public class DicAction extends ExtJSSimpleAction<Dic> {
    @Resource
    private DicService dicService;
    
    /**
     * 
     * 此类用来提供下拉列表服务,主要有两种下拉类型:
     * 一、普通下拉选项
     * 二、树形下拉选项
     * @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使用单例。json

单例必定比原型快吗?建立一个对象的开销能够忽略吗?这个问题须要在本身的场景中考虑,不过大多时候咱们是能够忽略的。后端

APDPlat以前使用struts2,每个请求都会对应一个全新的Action,因此请求的参数就能够做为Action的字段来自动注入,言下之意就是Action中的全部方法均可以共用字段,而如今换成spring mvc了,不一样的方法须要各自获取请求中的参数。mvc

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


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

使用struts2:

@Scope("prototype")
@Controller
@Namespace("/dictionary")
public class DicItemAction extends ExtJSSimpleAction<DicItem> {
    @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<DicItem> {
    @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<DicItem> {
    @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 "[]";
    }
}
相关文章
相关标签/搜索