在傳統的web應用開發中,大多數的程序員會將瀏覽器做爲先後端的分界線。將瀏覽器中爲用戶進行頁面展現的部分稱之爲前端,而將運行在服務器,爲前端提供業務邏輯和數據準備的全部代碼統稱爲後端。javascript
因爲先後端分離這個概念相對來講剛出現不久,不少人都是隻聞其聲,不見其形,因此可能會對它產生一些誤解,誤覺得先後端分離只是一種web應用開發模式,只要在web應用的開發期進行了先後端開發工做的分工就是先後端分離。html
其實先後端分離並不僅是開發模式,而是web應用的一種架構模式
。在開發階段,先後端工程師約定好數據交互接口,實現並行開發和測試;在運行階段先後端分離模式須要對web應用進行分離部署,先後端以前使用HTTP或者其餘協議進行交互請求。然而做爲一種架構模式,咱們在實施的過程當中主要對如下四個方面來進行比較和從新認識。前端
先後端分離大概能夠從四個方面來理解:java
在先後端分離架構中,後端只須要負責按照約定的數據格式向前端提供可調用的API服務便可。先後端之間經過HTTP請求進行交互,前端獲取到數據後,進行頁面的組裝和渲染,最終返回給瀏覽器。程序員
在傳統架構模式中,先後端代碼存放於同一個代碼庫中,甚至是同一工程目錄下。頁面中還夾雜着後端代碼。先後端工程師進行開發時,都必須把整個項目導入到開發工具中。web
而先後端分離模式在代碼組織形式上有如下兩種:json
咱們以前的架構屬於傳統的MVC架構,總體沒有進行先後端分離,在項目的開發階段,前端工程師負責編寫HTML,完成前端的頁面設計並套頁面,而後再使用模板技術將寫好的前端代碼轉換爲Smarty腳本,同時內嵌一些後端提供的模板變量和一些邏輯操做。應用運行期,將所有代碼進行打包,和後端代碼部署到同一服務器上,同時會進行簡單的動靜態分離部署。segmentfault
此時,應用的開發流程以下圖所示。後端
而在實現先後端分離架構以後,前端工程師只須要編寫HTML、js、CSS等前端資源,而後通 過HTTP請求調用後端提供的服務便可。除了開發期的分離,在運行期先後端資源也 會進行分離部署。瀏覽器
先後端分離以後,開發流程將以下圖所示。
經過上面的兩幅流程圖,不難發現,在開發模式上,先後段分離不只僅只是工程師的分工開發,更重要的意義在於實現了先後端的並行開發,簡化了開發流程
。
在開發期間先後端共同商定好數據接口的交互形式和數據格式。而後實現先後端的並行開發,其中前端工程師再開發完成以後能夠獨自進行mock測試,然後端也可使用接口測試平臺進行接口自測,而後先後端一塊兒進行功能聯調並校驗格式,最終進行自動化測試。
先後端分離模式和傳統的web應用架構相比有很大的不一樣,到底分仍是不分,這還真是個問題。
從目前應用軟件開發的發展趨勢來看,主要有兩方面須要注意:
咱們主要經過先後端分離架構,爲咱們帶來如下四個方面的提高:
應用代碼將會變得整潔清晰,不管是代碼閱讀仍是代碼維護都會比之前輕鬆。
以上轉自先後端分離實踐(一)
在本身最近作的項目中,使用的是利用SSM框架中的controller層來傳出JSON串,再經過jQuery中的.getJSON()
來進行解析,再將數據傳到前端頁面。
部分代碼省略,放出關鍵代碼:
ShopManagementController
@Controller @RequestMapping("/shopadmin") public class ShopManagementController { @Autowired private ShopService shopService; @Autowired private ShopCategoryService shopCategoryService; @Autowired private AreaService areaService; @RequestMapping(value = "/getshopmanagementinfo",method = RequestMethod.GET) @ResponseBody private Map<String,Object> getShopManagementInfo(HttpServletRequest request) { Map<String,Object> modelMap = new HashMap<String, Object>(); long shopId = HttpServletRequestUtil.getLong(request,"shopId"); if(shopId <= 0){ Object currentShopObj = request.getSession().getAttribute("shopId"); if(currentShopObj == null){ modelMap.put("redirect",true); modelMap.put("url","/shopadmin/shoplist"); }else { Shop currentShop = (Shop) currentShopObj; modelMap.put("redirect",false); modelMap.put("shopId",currentShop.getShopId()); } }else{ Shop currentShop = new Shop(); currentShop.setShopId(shopId); request.getSession().setAttribute("currentShop",currentShop); modelMap.put("redirect",false); } return modelMap; } @RequestMapping(value = "/getshoplist",method = RequestMethod.GET) @ResponseBody private Map<String,Object> getShopList(HttpServletRequest request){ Map<String,Object> modelMap = new HashMap<String, Object>(); PersonInfo user = new PersonInfo(); user.setUserId(1L); user.setName("test"); request.getSession().setAttribute("user",user); user = (PersonInfo) request.getSession().getAttribute("user"); try{ Shop shopCondition; shopCondition = new Shop(); shopCondition.setOwner(user); ShopExecution se = shopService.getShopList(shopCondition,0,100); modelMap.put("shopList",se.getShopList()); modelMap.put("user",user); modelMap.put("success",true); }catch (Exception e){ modelMap.put("success",false); modelMap.put("errMsg",e.getMessage()); } return modelMap; } @RequestMapping(value = "/getshopbyid",method = RequestMethod.GET) @ResponseBody private Map<String,Object> getShopById(HttpServletRequest request){ Map<String,Object> modelMap = new HashMap<String,Object>(); Long shopId = HttpServletRequestUtil.getLong(request,"shopId"); if(shopId > -1){ try { Shop shop = shopService.getByShopId(shopId); List<Area> areaList = areaService.getAreaList(); modelMap.put("shop",shop); modelMap.put("areaList",areaList); modelMap.put("success",true); }catch (Exception e){ modelMap.put("success",false); modelMap.put("errMsg",e.getMessage()); } }else { modelMap.put("success",false); modelMap.put("errMsg","empty shopId"); } return modelMap; } @RequestMapping(value = "/getshopinitinfo",method = RequestMethod.GET) @ResponseBody public Map<String,Object> getShopInitInfo(){ Map<String,Object> modelMap = new HashMap<String, Object>(); List<ShopCategory> shopCategoryList = new ArrayList<ShopCategory>(); List<Area> areaList = new ArrayList<Area>(); try { shopCategoryList = shopCategoryService.getShopCategoryList(new ShopCategory()); areaList = areaService.getAreaList(); modelMap.put("shopCategoryList",shopCategoryList); modelMap.put("areaList",areaList); modelMap.put("success",true); }catch (Exception e){ modelMap.put("success",false); modelMap.put("errMsg",e.getMessage()); } return modelMap; } @RequestMapping(value = "/modifyshop",method = {RequestMethod.POST}) @ResponseBody public Map<String,Object> modifyShop(HttpServletRequest request) throws IOException { Map<String,Object> modelMap = new HashMap<String, Object>(); //判斷驗證碼是否正確 if(!CodeUtil.checkVerifyCode(request)){ modelMap.put("success",false); modelMap.put("errMsg","輸入了錯誤的驗證碼"); return modelMap; } //1.接收並轉化相應的參數,包括店鋪信息以及圖片信息 String shopStr = HttpServletRequestUtil.getString(request,"shopStr"); ObjectMapper mapper = new ObjectMapper(); Shop shop = null; try { shop = mapper.readValue(shopStr,Shop.class); }catch (Exception e){ modelMap.put("success",false); modelMap.put("errMsg",e.getMessage()); return modelMap; } CommonsMultipartFile shopImg = null; CommonsMultipartResolver commonsMultipartResolver =new CommonsMultipartResolver( request.getSession().getServletContext()); // 檢測文件是否有上傳文件流 if (commonsMultipartResolver.isMultipart(request)){ MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request; shopImg = (CommonsMultipartFile) multipartHttpServletRequest.getFile("shopImg"); } //2.修改店鋪信息 if(shop != null && shop.getShopId() != null){ PersonInfo owner =(PersonInfo) request.getSession().getAttribute("user"); // session owner.setUserId(1L); shop.setOwner(owner); ShopExecution se; try { if (shopImg == null){ se = shopService.modifyShop(shop, new ImageHolder(null, null)); }else { se = shopService.modifyShop(shop, new ImageHolder(shopImg.getInputStream(), shopImg.getOriginalFilename())); } if(se.getState()==ShopStateEnum.SUCCESS.getState()){ modelMap.put("success",true); }else { modelMap.put("success",false); modelMap.put("errMsg",se.getStateInfo()); } }catch (ShopOperationException e){ modelMap.put("success",false); modelMap.put("errMsg",e.getMessage()); } catch (IOException e){ modelMap.put("success",false); modelMap.put("errMsg",e.getMessage()); } return modelMap; }else { modelMap.put("success",false); modelMap.put("errMsg","請輸入店鋪Id"); return modelMap; } } }
拿getShopById
作分析
//返回/getshopbyid的url,方法爲get @RequestMapping(value = "/getshopbyid",method = RequestMethod.GET) //返回JSON串 @ResponseBody private Map<String,Object> getShopById(HttpServletRequest request){ //初始化要返回的JSON串 Map<String,Object> modelMap = new HashMap<String,Object>(); //從Http請求中得到shopId值 Long shopId = HttpServletRequestUtil.getLong(request,"shopId"); if(shopId > -1){ try { /** * 下面代碼作service層查詢,得到商店Id爲shopId的商店信息 */ Shop shop = shopService.getByShopId(shopId); List<Area> areaList = areaService.getAreaList(); modelMap.put("shop",shop); modelMap.put("areaList",areaList); modelMap.put("success",true); }catch (Exception e){ modelMap.put("success",false); modelMap.put("errMsg",e.getMessage()); } }else { modelMap.put("success",false); modelMap.put("errMsg","empty shopId"); } return modelMap; }
再來看看前端頁面是如何處理的。
(function() { var shopId = getQueryString('shopId'); var isEdit = shopId?true:false; var initUrl = '/shopadmin/getshopinitinfo'; var registerShopUrl = '/shopadmin/registershop'; //訪問/shopadmin/getshopbyid這個url var shopInfoUrl = "/shopadmin/getshopbyid?shopId=" + shopId;
//從/shopadmin/getshopbyid?shopId這個url中得到controller層返回的JSON串,經過$.getJSON函數進行解析。 //獲取相關的鍵值對,而後插入前端HTML頁面。 function getShopInfoUrl(shopId) { $.getJSON(shopInfoUrl,function (data) { if(data.success){ var shop = data.shop; $('#shop-name').val(shop.shopName); $('#shop-addr').val(shop.shopAddr); $('#shop-phone').val(shop.phone); $('#shop-desc').val(shop.shopDesc); var shopCategory = '<option data-id="' + shop.shopCategory.shopCategoryId +'"selected>' + shop.shopCategory.shopCategoryName +'</option>'; var tempAreaHtml = ''; data.areaList.map(function (item,index) { tempAreaHtml += '<option data-id="' + item.areaId+'"selected>' + item.areaName+'</option>'; }); $('#shop-category').html(shopCategory); $('#shop-category').attr('disable','disable'); $('#shop-area').html(tempAreaHtml); $("#shop-area option[data-id='"+shop.area.areaId+"']").attr("selected","selected"); } }); }
訪問url,便可得到商店信息
流程圖: