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 "[]";
    }
}
相關文章
相關標籤/搜索