最近我在將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 "[]"; } }