大家好,今天小編來為大家解答以下的問題,關(guān)于聯(lián)想t430s筆記本是哪一年出的,聯(lián)想t430s筆記本配置,聯(lián)想t430s筆記本是哪一年出的,聯(lián)想t430s筆記本配置這個(gè)很多人還不知道,現(xiàn)在讓我們一起來看看吧!聯(lián)想512GB移動(dòng)固態(tài)到手價(jià)389元辦公必備對(duì)于現(xiàn)在辦公室上班族和學(xué)生一族來說,妥善的保存資料是很重要的事。聯(lián)想推出的ZX1系列移動(dòng)固態(tài)硬盤,以時(shí)尚的外觀,快速的存儲(chǔ)速度,非常適合上班族
大家好,今天小編來為大家解答以下的問題,關(guān)于聯(lián)想t430s筆記本是哪一年出的,聯(lián)想t430s筆記本配置,聯(lián)想t430s筆記本是哪一年出的,聯(lián)想t430s筆記本配置這個(gè)很多人還不知道,現(xiàn)在讓我們一起來看看吧!
聯(lián)想512GB移動(dòng)固態(tài)到手價(jià)389元 辦公必備
對(duì)于現(xiàn)在辦公室上班族和學(xué)生一族來說,妥善的保存資料是很重要的事。聯(lián)想推出的ZX1系列移動(dòng)固態(tài)硬盤,以時(shí)尚的外觀,快速的存儲(chǔ)速度,非常適合上班族和學(xué)生使用。在京東商城聯(lián)想SSD京東自營旗艦店,聯(lián)想ZX1移動(dòng)固態(tài)硬盤512GB秒殺價(jià)僅為389元,值得關(guān)注。
聯(lián)想ZX1移動(dòng)固態(tài)硬盤采用金屬盤神設(shè)計(jì),外觀修長,便于攜帶。在傳輸協(xié)議上,聯(lián)想ZX1采用了U** 3.1 Gen 2協(xié)議,提供430MB/s讀寫速度和400MB/s寫入速度,輕松完成大容量文件、視頻、文件傳輸。
(7913674)
SSH和S**的區(qū)別,抽絲剝繭由內(nèi)到外給你講清楚
SSH 通常指的是 Struts2 做前端控制器,Spring 管理各層的組件,Hibernate 負(fù)責(zé)持久化層。
S** 則指的是 SpringMVC 做前端控制器,Spring 管理各層的組件,MyBatis 負(fù)責(zé)持久化層。
共同之處是都使用了Spring的依賴注入DI來管理各層的組件,使用了面向切面編程AOP來實(shí)現(xiàn)日志管理,權(quán)限認(rèn)證,事務(wù)等通用功能的切入。
不同之處是 Struts2 和 SpringMVC 做前端控制器的區(qū)別,以及 Hibernate 和 MyBatis 做持久化時(shí)的區(qū)別。但是,Struts2 也可以和 MyBatis 搭配使用,SpringMVC 也可以和 Hibernate 搭配使用。本文為了簡化對(duì)比,指定 Struts2 要和 Hibernate 搭配,SpringMVC 要和 MyBatis 搭配。
1.1. SSH 和 S** 的實(shí)現(xiàn)原理區(qū)別
所在分層SSHS**頁面層(View)JSPJSP控制器層(Controller)Struts2SpringMVC業(yè)務(wù)層(Service)JavaJava持久層(DAO)HibernateMyBatis數(shù)據(jù)庫層(DB)MySQL/OracleMySQL/Oracle組件管理(Bean)SpringSpring
(1) Struts2 的原理
一個(gè)請(qǐng)求在Struts2框架中的處理大概分為以下幾個(gè)步驟:
1、客戶端初始化一個(gè)指向Servlet容器(例如Tomcat)的請(qǐng)求
2、這個(gè)請(qǐng)求經(jīng)過一系列的過濾器(Filter)(這些過濾器中有一個(gè)叫做ActionContextCleanUp的可選過濾器,這個(gè)過濾器對(duì)于Struts2和其他框架的集成很有幫助,例如:SiteMesh Plugin)
3、接著FilterDispatcher被調(diào)用,F(xiàn)ilterDispatcher詢問ActionMapper來決定這個(gè)請(qǐng)求是否需要調(diào)用某個(gè)Action
FilterDispatcher是控制器的核心,就是mvc中c控制層的核心。下面粗略的分析下FilterDispatcher工作流程和原理:FilterDispatcher進(jìn)行初始化并啟用核心doFilter。
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { showDeprecatedWarning(); HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; ServletContext servletContext = getServletContext(); String timerKey = “FilterDispatcher_doFilter: “; try { // FIXME: this should be refactored better to not duplicate work with the action invocation ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack(); ActionContext ctx = new ActionContext(stack.getContext()); ActionContext.setContext(ctx); UtilTimerStack.push(timerKey); request = prepareDispatcherAndWrapRequest(request, response); ActionMapping mapping; try { //在這里找到Action的映射器 mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager()); } catch (Exception ex) { log.error(“error getting ActionMapping”, ex); dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex); return; } //沒有此Action的話,就去查找靜態(tài)資源 if (mapping == null) { // there is no action in this request, should we look for a static resource? String resourcePath = RequestUtils.getServletPath(request); if (“”.equals(resourcePath) && null != request.getPathInfo()) { resourcePath = request.getPathInfo(); } if (staticResourceLoader.canHandle(resourcePath)) { staticResourceLoader.findStaticResource(resourcePath, request, response); } else { // this is a normal request, let it pass through chain.doFilter(request, response); } // The framework did its job here return; } //有此Action的話則把控制權(quán)交給ActionProxy dispatcher.serviceAction(request, response, servletContext, mapping); } finally { dispatcher.cleanUpRequest(request); try { ActionContextCleanUp.cleanUp(req); } finally { UtilTimerStack.pop(timerKey); } devModeOverride.remove(); } }
4、如果ActionMapper決定需要調(diào)用某個(gè)Action,F(xiàn)ilterDispatcher把請(qǐng)求的處理交給ActionProxy
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context, ActionMapping mapping) throws ServletException { Map<String, Object> extraContext = createContextMap(request, response, mapping, context); // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY); boolean nullStack = stack == null; if (nullStack) { ActionContext ctx = ActionContext.getContext(); if (ctx != null) { stack = ctx.getValueStack(); } } if (stack != null) { extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack)); } String timerKey = “Handling request from Dispatcher”; try { UtilTimerStack.push(timerKey); String namespace = mapping.getNamespace(); String name = mapping.getName(); String method = mapping.getMethod(); //獲取配置文件 Configuration config = configurationManager.getConfiguration(); //根據(jù)配置文件找到此Action并生成ActionProxy ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy( namespace, name, method, extraContext, true, false); request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack()); // if the ActionMapping says to go straight to a result, do it! if (mapping.getResult() != null) { Result result = mapping.getResult(); //ActionProxy創(chuàng)建一個(gè)ActionInvocation的實(shí)例 result.execute(proxy.getInvocation()); } else { proxy.execute(); } // If there was a previous value stack then set it back onto the request if (!nullStack) { request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack); } } catch (ConfigurationException e) { logConfigurationException(request, e); sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e); } catch (Exception e) { if (handleException || devMode) { sendError(request, response, context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e); } else { throw new ServletException(e); } } finally { UtilTimerStack.pop(timerKey); } }
5、ActionProxy通過Configuration Manager詢問框架的配置文件,找到需要調(diào)用的Action類
6、ActionProxy創(chuàng)建一個(gè)ActionInvocation的實(shí)例。
7、ActionInvocation實(shí)例使用命名模式來調(diào)用,在調(diào)用Action的過程前后,涉及到相關(guān)**(Intercepter)的調(diào)用。
8、一旦Action執(zhí)行完畢,ActionInvocation負(fù)責(zé)根據(jù)struts.xml中的配置找到對(duì)應(yīng)的返回結(jié)果。返回結(jié)果通常是(但不總是,也可 能是另外的一個(gè)Action鏈)一個(gè)需要被表示的JSP或者FreeMarker的模版。
9、將處理結(jié)果返回給客戶端
(2) SpringMVC 的原理
執(zhí)行步驟:
第一步:發(fā)起請(qǐng)求到前端控制器(DispatcherServlet)
第二步:前端控制器請(qǐng)求HandlerMapping查找 Handler
可以根據(jù)xml配置、注解進(jìn)行查找
第三步:處理器映射器HandlerMapping向前端控制器返回Handler
第四步:前端控制器調(diào)用處理器適配器去執(zhí)行Handler
第五步:處理器適配器去執(zhí)行Handler
第六步:Handler執(zhí)行完成給適配器返回ModelAn**iew
第七步:處理器適配器向前端控制器返回ModelAn**iew
ModelAn**iew是SpringMVC框架的一個(gè)底層對(duì)象,包括 Model和view
第八步:前端控制器請(qǐng)求視圖解析器去進(jìn)行視圖解析
根據(jù)邏輯視圖名解析成真正的視圖(jsp)
第九步:視圖解析器向前端控制器返回View
第十步:前端控制器進(jìn)行視圖渲染
視圖渲染將模型數(shù)據(jù)(在ModelAn**iew對(duì)象中)填充到request域
第十一步:前端控制器向用戶響應(yīng)結(jié)果
(3) Hibernate 的原理
1.通過Configuration().configure();讀取并解析hibernate.cfg.xml配置文件
2.由hibernate.cfg.xml中的<mapping resource=”com/xx/User.hbm.xml”/>讀取并解析映射信息
3.通過config.buildSessionFactory();//創(chuàng)建SessionFactory
4.sessionFactory.openSession();//打開Sesssion
5.session.beginTransaction();//創(chuàng)建事務(wù)Transation
6.persistent operate持久化**作
7.session.getTransaction().commit();//提交事務(wù)
8.關(guān)閉Session
9.關(guān)閉SesstionFactory
(4) MyBatis原理
MyBatis框架執(zhí)行過程:
1、配置MyBatis的配置文件,SqlMapConfig.xml(名稱不固定)
2、通過配置文件,加載MyBatis運(yùn)行環(huán)境,創(chuàng)建SqlSessionFactory會(huì)話工廠
SqlSessionFactory 在實(shí)際使用時(shí)按單例方式。
3、通過SqlSessionFactory創(chuàng)建SqlSession
SqlSession 是一個(gè)面向用戶接口(提供**作數(shù)據(jù)庫方法),實(shí)現(xiàn)對(duì)象是線程不安全的,建議sqlSession應(yīng)用場(chǎng)合在方法體內(nèi)。
4、調(diào)用 sqlSession 的方法去**作數(shù)據(jù)。
如果需要提交事務(wù),需要執(zhí)行 SqlSession 的 commit() 方法。
5、釋放資源,關(guān)閉SqlSession
1.2. Struts2 和 SpringMVC 在 web.xml 中配置的不同
(1) Struts2
<filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> <init-param> <param-name>filterConfig</param-name> <param-value>classpath:struts2/struts.xml</param-value> </init-param> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Struts2使用Filter嵌入自己的框架。配置文件加載順序?yàn)椋篸efault.properties -> struts-default.xml -> struts-plugins.xml -> struts.xml -> struts.locale。
加載順序可以參考這篇文章的源碼分析了解更多。
(2) SpringMVC
<!– springmvc前端控制器,rest配置 –> <servlet> <servlet-name>springmvc_rest</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!– contextConfigLocation配置springmvc加載的配置文件(配置處理器映射器、適配器等等) 如果不配置contextConfigLocation,默認(rèn)加載的是/WEB-INF/servlet名稱-serlvet.xml(springmvc-servlet.xml) –> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc_rest</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
SpringMVC使用Servlet嵌入自己的框架。
(3)web.xml不同之處
SpringMVC的入口是Servlet,而Struts2是Filter(這里要指出,F(xiàn)ilter和Servlet是不同的。以前認(rèn)為filter是servlet的一種特殊),這就導(dǎo)致了二者的機(jī)制不同,這里就牽涉到Servlet和Filter的區(qū)別了。但是這只是接管用戶請(qǐng)求的兩種不同方式而已,控制權(quán)被Struts2和SpringMVC掌握之后,想做什么事都是可以做到的。
Servlet
servlet是一種運(yùn)行服務(wù)器端的java應(yīng)用程序,具有**于平臺(tái)和協(xié)議的特性,并且可以動(dòng)態(tài)的生成web頁面,它工作在客戶端請(qǐng)求與服務(wù)器響應(yīng)的中間層。最早支持 Servlet 技術(shù)的是 JavaSoft 的 Java Web Server。此后,一些其它的基于 Java 的 Web Server 開始支持標(biāo)準(zhǔn)的 Servlet API。Servlet 的主要功能在于交互式地瀏覽和修改數(shù)據(jù),生成動(dòng)態(tài) Web 內(nèi)容。這個(gè)過程為:
1) 客戶端發(fā)送請(qǐng)求至服務(wù)器端;2) 服務(wù)器將請(qǐng)求信息發(fā)送至 Servlet;3) Servlet 生成響應(yīng)內(nèi)容并將其傳給服務(wù)器。響應(yīng)內(nèi)容動(dòng)態(tài)生成,通常取決于客戶端的請(qǐng)求;4) 服務(wù)器將響應(yīng)返回給客戶端。在 Web 應(yīng)用程序中,一個(gè) Servlet 在一個(gè)時(shí)刻可能被多個(gè)用戶同時(shí)訪問。這時(shí) Web 容器將為每個(gè)用戶創(chuàng)建一個(gè)線程來執(zhí)行 Servlet。如果 Servlet 不涉及共享資源的問題,不必關(guān)心多線程問題。但如果 Servlet 需要共享資源,需要保證 Servlet 是線程安全的。為了簡化開發(fā)流程,Servlet 3.0 引入了注解(annotation),這使得 web 部署描述符 web.xml 不再是必須的選擇
Filter:Filter是一個(gè)可以復(fù)用的代碼片段,可以用來轉(zhuǎn)換HTTP請(qǐng)求、響應(yīng)和頭信息。Filter不像Servlet,它不能產(chǎn)生一個(gè)請(qǐng)求或者響應(yīng),它只是修改對(duì)某一資源的請(qǐng)求,或者修改從某一的響應(yīng)。Servlet中的過濾器Filter是實(shí)現(xiàn)了javax.servlet.Filter接口的服務(wù)器端程序,主要的用途是過濾字符編碼、做一些業(yè)務(wù)邏輯判斷等。其工作原理是,只要你在web.xml文件配置好要攔截的客戶端請(qǐng)求,它都會(huì)幫你攔截到請(qǐng)求,此時(shí)你就可以對(duì)請(qǐng)求或響應(yīng)(Request、Response)統(tǒng)一設(shè)置編碼,簡化**作;同時(shí)還可進(jìn)行邏輯判斷,如用戶是否已經(jīng)登陸、有沒有權(quán)限訪問該頁面等等工作。它是隨你的web應(yīng)用啟動(dòng)而啟動(dòng)的,只初始化一次,以后就可以攔截相關(guān)請(qǐng)求,只有當(dāng)你的web應(yīng)用停止或重新部署的時(shí)候才銷毀。Filter可認(rèn)為是Servlet的一種“變種”,它主要用于對(duì)用戶請(qǐng)求進(jìn)行預(yù)處理,也可以對(duì)HttpServletResponse進(jìn)行后處理,是個(gè)典型的處理鏈。它與Servlet的區(qū)別在于:它不能直接向用戶生成響應(yīng)。完整的流程是:Filter對(duì)用戶請(qǐng)求進(jìn)行預(yù)處理,接著將請(qǐng)求交給Servlet進(jìn)行處理并生成響應(yīng),最后Filter再對(duì)服務(wù)器響應(yīng)進(jìn)行后處理。
1.3. Struts2 和 SpringMVC 處理用戶請(qǐng)求的不同
Struts2和SpringMVC的核心都是接管用戶的請(qǐng)求,解決傳統(tǒng)Servlet開發(fā)過于繁瑣,重用性不高的問題。
Struts2和SpringMVC都有注解和配置文件兩種匹配用戶請(qǐng)求URL的方式。
Struts2注解方式匹配URL
首先需要將架包(struts2-convention-plugin-xxx.jar)導(dǎo)入工程中
示例
package com.example.actions; import com.opensymphony.xwork2.ActionSupport; import org.apache.struts2.convention.annotation.Action; import org.apache.struts2.convention.annotation.Actions; import org.apache.struts2.convention.annotation.Result; import org.apache.struts2.convention.annotation.Results; @Results({ @Result(name=”failure”, location=”fail.jsp”) }) public class HelloWorld extends ActionSupport { @Action(value=”/different/url”, results={@Result(name=”success”, location=””, type=”redirect”)} ) public String execute() { return SUCCESS; } @Action(“/another/url”) public String doSomething() { return SUCCESS; } }
Struts2配置方式匹配URL
<package name=”package” namespace=”/different” extends=”struts-default”> <global-results> <result name=”failure”>/fail.jsp</result> </global-results> <action name=”url” class=”com.example.actions.HelloWorld” method=”execute”> <result name=”success” type=”redirect”></result> </action> </package> <package name=”package2″ namespace=”/another” extends=”struts-default”> <global-results> <result name=”failure”>/fail.jsp</result> </global-results> <action name=”url” class=”com.example.actions.HelloWorld” method=”doSomething”> </action> </package>
SpringMVC注解方式匹配URL
package com.jpkc.controller;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.servlet.ModelAn**iew;@RequestMapping(“/admin”)@Controllerpublic class LoginController{ @RequestMapping(“/admin_home”) public String admin_home() throws Exception { return “forward:/shop/index.jsp”; } @RequestMapping(“/exit”) public String logout(ModelAn**iew model, HttpSession session) throws Exception { session.invalidate(); return “redirect:/manager/login.jsp”; }}
SpringMVC配置方式匹配URL
public class ItemsController1 implements Controller { @Override public ModelAn**iew handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { //調(diào)用Service查找 數(shù)據(jù)庫,查詢商品列表,這里使用靜態(tài)數(shù)據(jù)模擬 List<Items> itemsList = new ArrayList<Items>(); //向list中填充靜態(tài)數(shù)據(jù) Items items_1 = new Items(); items_1.setName(“聯(lián)想筆記本”); items_1.setPrice(6000f); items_1.setDetail(“ThinkPad T430 聯(lián)想筆記本電腦!”); Items items_2 = new Items(); items_2.setName(“蘋果手機(jī)”); items_2.setPrice(5000f); items_2.setDetail(“iphone6蘋果手機(jī)!”); itemsList.add(items_1); itemsList.add(items_2); //返回ModelAn**iew ModelAn**iew modelAn**iew = new ModelAn**iew(); //相當(dāng) 于request的setAttribut,在jsp頁面中通過itemsList取數(shù)據(jù) modelAn**iew.addObject(“itemsList”, itemsList); //指定視圖 modelAn**iew.setViewName(“/WEB-INF/jsp/items/itemsList.jsp”); return modelAn**iew; }}
<!– 配置Handler –><bean id=”itemsController1″ name=”/queryItems.action” class=”cn.itcast.s**.controller.ItemsController1″ />
1、Struts2是類級(jí)別的攔截, 一個(gè)類對(duì)應(yīng)一個(gè)request上下文,SpringMVC是方法級(jí)別的攔截,一個(gè)方法對(duì)應(yīng)一個(gè)request上下文,而方法同時(shí)又跟一個(gè)url對(duì)應(yīng),所以說從架構(gòu)本身上SpringMVC就容易實(shí)現(xiàn)restful url,而struts2的架構(gòu)實(shí)現(xiàn)起來要費(fèi)勁,因?yàn)镾truts2中Action的一個(gè)方法可以對(duì)應(yīng)一個(gè)url,而其類屬性卻被所有方法共享,這也就無法用注解或其他方式標(biāo)識(shí)其所屬方法了。
2、由上邊原因,SpringMVC的方法之間基本上**的,獨(dú)享request response數(shù)據(jù),請(qǐng)求數(shù)據(jù)通過參數(shù)獲取,處理結(jié)果通過ModelMap交回給框架,方法之間不共享變量,而Struts2搞的就比較亂,雖然方法之間也是**的,但其所有Action變量是共享的,這不會(huì)影響程序運(yùn)行,卻給我們編碼 讀程序時(shí)帶來麻煩,每次來了請(qǐng)求就創(chuàng)建一個(gè)Action,一個(gè)Action對(duì)象對(duì)應(yīng)一個(gè)request上下文。
3、由于Struts2需要針對(duì)每個(gè)request進(jìn)行封裝,把request,session等servlet生命周期的變量封裝成一個(gè)一個(gè)Map,供給每個(gè)Action使用,并保證線程安全,所以在原則上,是比較耗費(fèi)內(nèi)存的。
1.4. Struts2 和 SpringMVC 實(shí)現(xiàn) RESTful 的不同
實(shí)現(xiàn)上面這個(gè)鏈接,其中l(wèi)ocalhost是域名,jpkc是項(xiàng)目名。
Struts2實(shí)現(xiàn)方式
<package name=”course_info_package” namespace=”/item” extends=”struts-default”> <action name=”*” class=”com.jpkc.action.CourseAction” method=”get_course_info”> <result name=”success”>/story/story_02.jsp</result> </action> </package>
public class CourseAction extends ActionSupport{ public String get_course_info() { String actionName = ServletActionContext.getActionMapping().getName(); CourseInfo courseInfoFromDB = courseInfoDAO.findById(actionName); if (courseInfoFromDB == null) { return “404”; } Course courseFromDB = courseDAO.findById(actionName); if (courseFromDB == null) { return “404”; } setCourseInfo(courseInfoFromDB); setCourse(courseFromDB); return SUCCESS; }}
SpringMVC實(shí)現(xiàn)方式
@Controllerpublic class CourseController{ @RequestMapping(“/item/{id}”) public ModelAn**iew get_course_info(ModelAn**iew model, @PathVariable(“id”) String id) { if (CM.validIsEmptyWithTrim(id)) { model.addObject(“message”, “沒有找到此視頻頁面”); model.setViewName(“/WEB-INF/jsp/error”); return model; } CourseInfo courseInfoFromDB=null; try { courseInfoFromDB = courseInfoService.selectByPrimaryKey(id); } catch (Exception e1) { System.out.println(“沒有找到課程信息”); } if (courseInfoFromDB == null) { model.addObject(“message”, “沒有找到此視頻頁面”); model.setViewName(“/WEB-INF/jsp/error”); return model; } Course courseFromDB = null; try { courseFromDB = courseService.selectByPrimaryKey(id); } catch (Exception e) { System.out.println(“沒有查找到課程”); } if (courseFromDB == null) { model.addObject(“message”, “沒有找到此視頻頁面”); model.setViewName(“/WEB-INF/jsp/error”); return model; } model.addObject(“courseInfo”, courseInfoFromDB); model.addObject(“course”, courseFromDB); model.setViewName(“/story/story_02”); return model; }}
對(duì)于類似于這種鏈接,Struts2實(shí)現(xiàn)RESTful風(fēng)格需要在代碼中調(diào)用ServletActionContext.getActionMapping().getName()獲取ActionName。SpringMVC直接將鏈接映射到方法參數(shù)里去了。
如果類似于這種鏈接,Struts2要進(jìn)一步分析鏈接得到id1和id2。SpringMVC依然可以將id2映射到方法參數(shù)上。從調(diào)用的角度來看SpringMVC要方便一些。但是如果將Struts2獲取方式封裝一下,也可以得到同樣的效果。
1.5. Struts2 和 SpringMVC 獲取 request 參數(shù)的不同
前臺(tái)頁面有一個(gè)表單需要提交。
Struts2 接收 request 參數(shù)
<form class=”login-form” action=”/login_do” method=”post”> <h3 class=”form-title”>登錄系統(tǒng)</h3> <div class=”alert alert-danger display-hide”> <button class=”close” data-close=”alert”></button> <span> 請(qǐng)輸入用戶名和密碼 </span> </div> <div class=”form-group”> <label class=”control-label visible-ie8 visible-ie9″>用戶名</label> <div class=”input-icon”> <i class=”fa fa-user”></i> <input class=”form-control placeholder-no-fix” type=”text” autocomplete=”off” placeholder=”用戶名” name=”account.id” /> </div> </div> <div class=”form-group”> <label class=”control-label visible-ie8 visible-ie9″>密碼</label> <div class=”input-icon”> <i class=”fa fa-lock”></i> <input class=”form-control placeholder-no-fix” type=”password” autocomplete=”off” placeholder=”密碼” name=”account.password” /> </div> </div> <div class=”form-actions”> <button type=”submit” class=”btn green pull-right”> 登錄 <i class=”m-icon-swapright m-icon-white”></i> </button> </div> </form>
package com.jpkc.pojo;import java.io.Serializable;public class Account implements Serializable{ private String id; private String password; private String name; public Account() { super(); // TODO Auto-generated constructor stub } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getName() { return name; } public void setName(String name) { this.name = name; }}
package com.jpkc.action;import java.util.HashMap;import java.util.Map;import com.jpkc.common.CM;import com.jpkc.pojo.Account;public class AccountAction extends BaseAction{ private Account account; public String login_do() { String method = getRequest().getMethod(); if (method.toUpperCase().equals(“GET”)) { return “404”; } if (account == null || CM.validIsEmpty(account.getId()) || CM.validIsEmpty(account.getPassword())) { return ERROR; } getSession().setAttribute(“accountSession”, account); return SUCCESS; } public Account getAccount() { return account; } public void setAccount(Account account) { this.account = account; }}
SpringMVC 接收 request 參數(shù)
<form class=”login-form” action=”admin/login_do” method=”post”> <h3 class=”form-title”>登錄系統(tǒng)</h3> <div class=”alert alert-danger display-hide”> <button class=”close” data-close=”alert”></button> <span> 請(qǐng)輸入用戶名和密碼 </span> </div> <div class=”form-group”> <label class=”control-label visible-ie8 visible-ie9″>用戶名</label> <div class=”input-icon”> <i class=”fa fa-user”></i> <input class=”form-control placeholder-no-fix” type=”text” autocomplete=”off” placeholder=”用戶名” name=”id” /> </div> </div> <div class=”form-group”> <label class=”control-label visible-ie8 visible-ie9″>密碼</label> <div class=”input-icon”> <i class=”fa fa-lock”></i> <input class=”form-control placeholder-no-fix” type=”password” autocomplete=”off” placeholder=”密碼” name=”password” /> </div> </div> <div class=”form-actions”> <button type=”submit” class=”btn green pull-right”> 登錄 <i class=”m-icon-swapright m-icon-white”></i> </button> </div> </form>
package com.jpkc.pojo;import java.io.Serializable;public class Account implements Serializable{ private String id; private String password; private String name; public Account() { super(); // TODO Auto-generated constructor stub } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getName() { return name; } public void setName(String name) { this.name = name; }}
package com.jpkc.controller;import java.util.HashMap;import java.util.Map;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import org.codehaus.jackson.map.ObjectMapper;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.servlet.ModelAn**iew;import com.jpkc.common.CM;import com.jpkc.exception.CustomException;import com.jpkc.mapper.CourseInfoMapper;import com.jpkc.pojo.Account;import com.jpkc.pojo.CourseInfo;import com.jpkc.service.LoginService;@RequestMapping(“/admin”)@Controllerpublic class LoginController{ @Autowired LoginService loginService; @RequestMapping(value = “/login_do”, method = { RequestMethod.POST }) public void login_do(ModelAn**iew model, HttpServletRequest request, HttpServletResponse response, HttpSession session, Account account) throws Exception { response.setCharacterEncoding(“utf-8”); response.setContentType(“application/json;charset=utf-8”); Map<String, Object> json = new HashMap<String, Object>(); String info; if (account == null || CM.validIsEmpty(account.getId()) || CM.validIsEmpty(account.getPassword())) { info = “用戶名、密碼都是必填項(xiàng)。”; json.put(“success”, false); json.put(“info”, info); response.getWriter().write(new ObjectMapper().writeValueAsString(json)); return; } session.setAttribute(“accountSession”, account); json.put(“success”, true); response.getWriter().write(new ObjectMapper().writeValueAsString(json)); return; }}
Struts2單個(gè)方法可以處理一個(gè)request,接收參數(shù)Account需要定義一個(gè)成員變量,Struts2會(huì)自動(dòng)將對(duì)應(yīng)的參數(shù)調(diào)用成員變量的set方法設(shè)置進(jìn)去。處理方法可以在方法內(nèi)獲取到。用完還存在request級(jí)別Map中。
SpringMVC的單個(gè)方法也對(duì)應(yīng)于一個(gè)request,接收參數(shù)Account需要定義一個(gè)方法參數(shù),SpringMVC會(huì)自動(dòng)將對(duì)應(yīng)的參數(shù)設(shè)置到方法參數(shù)中去。處理方法可以在方法內(nèi)獲取到。用完即銷毀。
可以看出兩種框架都可以實(shí)現(xiàn)參數(shù)的自動(dòng)轉(zhuǎn)換。Struts2定義一個(gè)成員變量,其他方法都是可以共享的,不用重新定義。SpringMVC每個(gè)方法都是**的,方法參數(shù)是每一個(gè)方法獨(dú)享的。
各有利弊。
成員變量共享可以避免重復(fù)定義,但是方法一多,用到的成員變量原來越多,整個(gè)Action類會(huì)慘不忍睹,因?yàn)槟悴恢榔渲幸粋€(gè)方法具體會(huì)用到哪幾個(gè)成員變量。而且用不到的成員變量也被存儲(chǔ)到request級(jí)別Map中了。造成內(nèi)存的浪費(fèi)。
方法參數(shù)是方法獨(dú)享的。則不能復(fù)用到其他方法,但是對(duì)于當(dāng)前方法來說有哪些參數(shù)足夠明確,而且不用和其他方法攪合,干脆利落。
從JVM角度來說,Struts2成員變量會(huì)被分配到堆中。SpringMVC方法參數(shù)則會(huì)存在于方法棧中,一般認(rèn)為棧比堆更輕量一些,方法結(jié)束,用完參數(shù)即回收。堆需要垃圾回收觸發(fā)時(shí)才能統(tǒng)一回收。
1.6. Struts2 和 SpringMVC 限制訪問方式GET和POST的不同
在上例中,表單提交有密碼,需要指定只接受POST提交方式。
Struts2指定POST方式
public String login_do() { String method = getRequest().getMethod(); if (method.toUpperCase().equals(“GET”)) { return “404”; } }
SpringMVC指定POST方式
@RequestMapping(value = “/login_do”, method = { RequestMethod.POST }) public void login_do(ModelAn**iew model, HttpServletRequest request, HttpServletResponse response, HttpSession session, Account account) throws Exception { response.setCharacterEncoding(“utf-8”); response.setContentType(“application/json;charset=utf-8”); Map<String, Object> json = new HashMap<String, Object>(); String info; if (account == null || CM.validIsEmpty(account.getId()) || CM.validIsEmpty(account.getPassword())) { info = “用戶名、密碼都是必填項(xiàng)。”; json.put(“success”, false); json.put(“info”, info); response.getWriter().write(new ObjectMapper().writeValueAsString(json)); return; } session.setAttribute(“accountSession”, account); json.put(“success”, true); response.getWriter().write(new ObjectMapper().writeValueAsString(json)); return; }
Struts2限制只能通過POST方式訪問,是通過調(diào)用request的getMethod方法來得到當(dāng)前訪問方式。然后手工的去判斷。
SpringMVC也可以調(diào)用request的getMethod方法來判斷,但是框架本身提供了方便的內(nèi)置判斷。使用注解即可。
Struts2通過**設(shè)置好訪問方式的代碼后,也可以通過注解的方式指定**得到同樣的效果。本身不是太難的事情,兩個(gè)框架都可以實(shí)現(xiàn),Struts2需要手工實(shí)現(xiàn),SpringMVC默認(rèn)提供了。即使SpringMVC不提供,調(diào)用SpringMVC的**也能和Struts2的**的效果一樣。在GET和POST訪問限制方面,并沒有誰優(yōu)誰劣,都可以實(shí)現(xiàn)。只是SpringMVC愿意往前多走一小步。
1.7. Struts2 和 SpringMVC **的不同
后臺(tái)頁面需要登錄,我們可以使用**限制未登錄的用戶訪問。
Struts2實(shí)現(xiàn)**的方式
public class ManagerLoginInterceptor extends AbstractInterceptor{ @Override public String intercept(ActionInvocation invocation) throws Exception { String actionName = ServletActionContext.getActionMapping().getName(); // 如果是登錄、注冊(cè)、退出的話就不要攔截了 if (actionName.equals(“exit”) || actionName.equals(“login”) || actionName.equals(“login_do”) || actionName.equals(“regist”) || actionName.equals(“regist_do”)) { return invocation.invoke(); } // 如果不是管理員就不能進(jìn)入 Manager managerTemp = (Manager) ServletActionContext.getRequest().getSession().getAttribute(“managerSession”); if (managerTemp == null) { return “manager_login”; } //驗(yàn)證成功,放行。 return invocation.invoke(); }}
<package name=”admin_package” namespace=”/admin” extends=”ssh-default”> <interceptors> <interceptor name=”LoginManagerValidate” class=”com.example.interceptor.ManagerLoginInterceptor”> </interceptor> <!– 自定義**棧-攔截未登錄的管理員- –> <interceptor-stack name=”LoginManagerValidateStack”> <interceptor-ref name=”LoginManagerValidate”></interceptor-ref> <interceptor-ref name=”defaultStack”></interceptor-ref> </interceptor-stack> </interceptors> <action name=”m_*” class=”com.example.action.ManagerAction” method=”m_{1}”> <interceptor-ref name=”LoginManagerValidateStack”></interceptor-ref> <result name=”success” type=”json”> <param name=”root”>json</param> </result> </action> </package>
Struts2還提供了很多默認(rèn)的**供用戶調(diào)用。
<interceptors> <interceptor name=”alias”class=”com.opensymphony.xwork2.interceptor.AliasInterceptor”/> <interceptor name=”autowiring”class=”com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor”/> <interceptor name=”chain”class=”com.opensymphony.xwork2.interceptor.ChainingInterceptor”/> <interceptor name=”conversionError”class=”org.apache.struts2.interceptor.StrutsConversionErrorInterceptor”/> <interceptor name=”clearSession”class=”org.apache.struts2.interceptor.ClearSessionInterceptor”/> <interceptor name=”createSession”class=”org.apache.struts2.interceptor.CreateSessionInterceptor”/> <interceptor name=”debugging”class=”org.apache.struts2.interceptor.debugging.DebuggingInterceptor”/> <interceptor name=”externalRef”class=”com.opensymphony.xwork2.interceptor.ExternalReferencesInterceptor”/> <interceptor name=”execAndWait”class=”org.apache.struts2.interceptor.ExecuteAndWaitInterceptor”/> <interceptor name=”exception”class=”com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor”/> <interceptor name=”fileUpload”class=”org.apache.struts2.interceptor.FileUploadInterceptor”/> <interceptor name=”i18n”class=”com.opensymphony.xwork2.interceptor.I18nInterceptor”/> <interceptor name=”logger”class=”com.opensymphony.xwork2.interceptor.LoggingInterceptor”/> <interceptor name=”modelDriven”class=”com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor”/> <interceptor name=”scopedModelDriven”class=”com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor”/> <interceptor name=”params”class=”com.opensymphony.xwork2.interceptor.ParametersInterceptor”/> <interceptor name=”actionMappingParams”class=”org.apache.struts2.interceptor.ActionMappingParametersInteceptor”/> <interceptor name=”prepare”class=”com.opensymphony.xwork2.interceptor.PrepareInterceptor”/> <interceptor name=”staticParams”class=”com.opensymphony.xwork2.interceptor.StaticParametersInterceptor”/> <interceptor name=”scope”class=”org.apache.struts2.interceptor.ScopeInterceptor”/> <interceptor name=”servletConfig”class=”org.apache.struts2.interceptor.ServletConfigInterceptor”/> <interceptor name=”sessionAutowiring”class=”org.apache.struts2.spring.interceptor.SessionContextAutowiringInterceptor”/> <interceptor name=”timer”class=”com.opensymphony.xwork2.interceptor.TimerInterceptor”/> <interceptor name=”token”class=”org.apache.struts2.interceptor.TokenInterceptor”/> <interceptor name=”tokenSession”class=”org.apache.struts2.interceptor.TokenSessionStoreInterceptor”/> <interceptor name=”validation”class=”org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor”/> <interceptor name=”workflow”class=”com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor”/> <interceptor name=”store”class=”org.apache.struts2.interceptor.MessageStoreInterceptor”/> <interceptor name=”checkbox”class=”org.apache.struts2.interceptor.CheckboxInterceptor”/> <interceptor name=”profiling”class=”org.apache.struts2.interceptor.ProfilingActivationInterceptor”/> <interceptor name=”roles”class=”org.apache.struts2.interceptor.RolesInterceptor”/> <interceptor name=”jsonValidation”class=”org.apache.struts2.interceptor.validation.JSONValidationInterceptor”/> <interceptornameinterceptorname=”annotationWorkflow”class=”com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor”/>
SpringMVC實(shí)現(xiàn)**的方式
public class LoginInterceptor implements HandlerInterceptor{ // 進(jìn)入 Handler方法之前執(zhí)行 // 用于身份認(rèn)證、身份授權(quán) // 比如身份認(rèn)證,如果認(rèn)證通過表示當(dāng)前用戶沒有登陸,需要此方法攔截不再向下執(zhí)行 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 獲取請(qǐng)求的url String url = request.getRequestURI(); // 判斷url是否是公開 地址(實(shí)際使用時(shí)將公開 地址配置配置文件中) // 這里公開地址是登陸提交的地址 if (url.indexOf(“login”) >= 0 || url.indexOf(“exit”) >= 0) { // 如果進(jìn)行登陸提交,放行 return true; } // 判斷session HttpSession session = request.getSession(); // 從session中取出用戶身份信息 Account account = (Account) session.getAttribute(“accountSession”); if (account != null) { // 身份存在,放行 return true; } // 執(zhí)行這里表示用戶身份需要認(rèn)證,跳轉(zhuǎn)登陸頁面 request.getRequestDispatcher(“/manager/login.jsp”).forward(request, response); // return false表示攔截,不向下執(zhí)行 // return true表示放行 return false; } // 進(jìn)入Handler方法之后,返回modelAn**iew之前執(zhí)行 // 應(yīng)用場(chǎng)景從modelAn**iew出發(fā):將公用的模型數(shù)據(jù)(比如菜單導(dǎo)航)在這里傳到視圖,也可以在這里統(tǒng)一指定視圖 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAn**iew modelAn**iew) throws Exception { System.out.println(“HandlerInterceptor1…postHandle”); } // 執(zhí)行Handler完成執(zhí)行此方法 // 應(yīng)用場(chǎng)景:統(tǒng)一異常處理,統(tǒng)一日志處理 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println(“HandlerInterceptor1…afterCompletion”); }}
<!–** –> <mvc:interceptors> <!–多個(gè)**,順序執(zhí)行 –> <!– 登錄認(rèn)證** –> <mvc:interceptor> <mvc:mapping path=”/admin/**” /> <bean class=”com.jpkc.interceptor.LoginInterceptor”></bean> </mvc:interceptor> </mvc:interceptors>
**實(shí)現(xiàn)機(jī)制上,Struts2有自己的interceptor機(jī)制,SpringMVC用的是**的AOP方式。都可以實(shí)現(xiàn)在前后進(jìn)行攔截。
1.8. Struts2 和 SpringMVC 支持 JSON 的不同
有時(shí)我們界面的一些**作,是通過 Ajax 調(diào)用后臺(tái)的服務(wù),獲取服務(wù)器返回的 json 數(shù)據(jù),進(jìn)行后續(xù)的**作。
Struts2 實(shí)現(xiàn)JSON數(shù)據(jù)返回的方式
<action name=”login_do” class=”com.jpkc.action.AccountAction” method=”login_do”> <result name=”success” type=”json”> <!– 這里指定將被Struts2序列化的屬性,該屬性在action中必須有對(duì)應(yīng)的getter方法 –> <param name=”root”>json</param> </result> </action>
public class AccountAction extends BaseAction{ // 常用變量 private Map<String, Object> json;// 返回到前臺(tái)的map對(duì)象 private Account account; public AccountAction() { json = new HashMap<String, Object>(); } public String login_do() { if (account == null || CM.validIsEmpty(account.getId()) || CM.validIsEmpty(account.getPassword())) { info = “用戶名、密碼都是必填項(xiàng)。”; json.put(“success”, false); json.put(“info”, info); return SUCCESS; } getSession().setAttribute(“accountSession”, account); json.put(“success”, true); return SUCCESS; }}
$.post(“login_do”, $(“.login-form”).serialize(), function(json){ if (json.success == true) { window.location.href=”shop/index.jsp”; } else { alert(“**作失?。?#8221; + json.info); }}, “json”);
SpringMVC 實(shí)現(xiàn)JSON數(shù)據(jù)返回的方式
<!–注解適配器 –> <bean class=”org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter”> <property name=”messageConverters”> <list> <bean class=”org.springframework.http.converter.json.MappingJackson2HttpMessageConverter”></bean> </list> </property> </bean>
$.post(“login_do”, $(“.login-form”).serialize(), function(json){ if (json.success == true) { window.location.href=”shop/index.jsp”; } else { alert(“**作失敗:” + json.info); }}, “json”);
SpringMVC在控制器中返回json有兩種方式。
一種是使用response返回json。
@RequestMapping(value = “/login_do”, method = { RequestMethod.POST }) public void login_do(ModelAn**iew model, HttpServletRequest request, HttpServletResponse response, HttpSession session, Account account) throws Exception { response.setCharacterEncoding(“utf-8”); response.setContentType(“application/json;charset=utf-8”); Map<String, Object> json = new HashMap<String, Object>(); String info; if (account == null || CM.validIsEmpty(account.getId()) || CM.validIsEmpty(account.getPassword())) { info = “用戶名、密碼都是必填項(xiàng)。”; json.put(“success”, false); json.put(“info”, info); response.getWriter().write(new ObjectMapper().writeValueAsString(json)); return; } session.setAttribute(“accountSession”, account); json.put(“success”, true); response.getWriter().write(new ObjectMapper().writeValueAsString(json)); return; }
另一種是使用@ResponseBody注解方式。
@RequestMapping(value = “/login_do”, method = { RequestMethod.POST }) public @ResponseBody Map<String, Object> login_do(ModelAn**iew model, HttpServletRequest request, HttpServletResponse response, HttpSession session, Account account) throws Exception { Map<String, Object> json = new HashMap<String, Object>(); String info; if (account == null || CM.validIsEmpty(account.getId()) || CM.validIsEmpty(account.getPassword())) { info = “用戶名、密碼都是必填項(xiàng)。”; json.put(“success”, false); json.put(“info”, info); return json; } session.setAttribute(“accountSession”, account); json.put(“success”, true); return json; }
可以看出,Struts2 和 SpringMVC 都可以實(shí)現(xiàn) Ajax 請(qǐng)求返回 JSON。實(shí)現(xiàn)方式上,Struts2在配置文件配置返回類型為JSON。SpringMVC在方法上加一個(gè)@ResponseBody注解即可返回對(duì)應(yīng)類型轉(zhuǎn)成的JSON字符串。都是對(duì)返回?cái)?shù)據(jù)轉(zhuǎn)成JSON,但是不得不說SpringMVC的寫法方便太多了。
1.9. Hibernate 和 MyBatis 在 ORM 側(cè)重點(diǎn)的不同
Hibernate對(duì)數(shù)據(jù)庫結(jié)構(gòu)提供了較為完整的封裝,Hibernate的O/R Mapping實(shí)現(xiàn)了POJO 和數(shù)據(jù)庫表之間的映射,以及SQL 的自動(dòng)生成和執(zhí)行。程序員往往只需定義好了POJO 到數(shù)據(jù)庫表的映射關(guān)系,即可通過Hibernate 提供的方法完成持久層**作。程序員甚至不需要對(duì)SQL 的熟練掌握, Hibernate/O** 會(huì)根據(jù)指定的存儲(chǔ)邏輯,自動(dòng)生成對(duì)應(yīng)的SQL 并調(diào)用JDBC 接口加以執(zhí)行。
MyBatis 的著力點(diǎn),則在于POJO 與SQL之間的映射關(guān)系。然后通過映射配置文件,將SQL所需的參數(shù),以及返回的結(jié)果字段映射到指定POJO。 相對(duì)Hibernate“O/R”而言,MyBatis 是一種“Sql Mapping”的ORM實(shí)現(xiàn)。
SQL語句支持:Hibernate可以完全不用手寫SQL語句,MyBatis手動(dòng)維護(hù)SQL語句。Hibernate修改優(yōu)化SQL語句困難,MyBatis由于SQL語句自己控制,優(yōu)化非常方便。
開發(fā)速度:Hibernate的真正掌握要比Mybatis來得難些。Mybatis框架相對(duì)簡單很容易上手,但也相對(duì)簡陋些。
開發(fā)社區(qū):Hibernate 與Mybatis都是流行的持久層開發(fā)框架,但Hibernate開發(fā)社區(qū)相對(duì)多熱鬧些,支持的工具也多,更新也快。而Mybatis相對(duì)平靜,工具較少。
開發(fā)工作量:Hibernate和MyBatis都有相應(yīng)的代碼生成工具??梢陨珊唵位镜腄AO層方法。
針對(duì)高級(jí)查詢,Mybatis需要手動(dòng)編寫SQL語句,以及ResultMap。而Hibernate有良好的映射機(jī)制,開發(fā)者無需關(guān)心SQL的生成與結(jié)果映射,可以更專注于業(yè)務(wù)流程。
1.10. Hibernate 和 MyBatis 在調(diào)優(yōu)方面的不同制定合理的緩存策略;盡量使用延遲加載特性;采用合理的Session管理機(jī)制;
SQL優(yōu)化方面
Hibernate的查詢會(huì)將表中的所有字段查詢出來,這一點(diǎn)會(huì)有性能消耗。Hibernate也可以自己寫SQL來指定需要查詢的字段,但這樣就破壞了Hibernate開發(fā)的簡潔性。而Mybatis的SQL是手動(dòng)編寫的,所以可以按需求指定查詢的字段。
Hibernate HQL語句的調(diào)優(yōu)需要將SQL打印出來,而Hibernate的SQL被很多人嫌棄因?yàn)樘罅?。MyBatis的SQL是自己手動(dòng)寫的所以調(diào)整方便。但Hibernate具有自己的日志統(tǒng)計(jì)。Mybatis本身不帶日志統(tǒng)計(jì),使用Log4j進(jìn)行日志記錄。
擴(kuò)展性方面
Hibernate與具體數(shù)據(jù)庫的關(guān)聯(lián)只需在XML文件中配置即可,所有的HQL語句與具體使用的數(shù)據(jù)庫無關(guān),移植性很好。MyBatis項(xiàng)目中所有的SQL語句都是依賴所用的數(shù)據(jù)庫的,所以不同數(shù)據(jù)庫類型的支持不好。
1.11. Hibernate 和 MyBatis 在對(duì)象管理與抓取策略的不同
對(duì)象管理
Hibernate 是完整的對(duì)象/關(guān)系映射解決方案,它提供了對(duì)象狀態(tài)管理(state management)的功能,使開發(fā)者不再需要理會(huì)底層數(shù)據(jù)庫系統(tǒng)的細(xì)節(jié)。也就是說,相對(duì)于常見的 JDBC/SQL 持久層方案中需要管理 SQL 語句,Hibernate采用了更自然的面向?qū)ο蟮囊暯莵沓志没?Java 應(yīng)用中的數(shù)據(jù)。
換句話說,使用 Hibernate 的開發(fā)者應(yīng)該總是關(guān)注對(duì)象的狀態(tài)(state),不必考慮 SQL 語句的執(zhí)行。這部分細(xì)節(jié)已經(jīng)由 Hibernate 掌管妥當(dāng),只有開發(fā)者在進(jìn)行系統(tǒng)性能調(diào)優(yōu)的時(shí)候才需要進(jìn)行了解。
而MyBatis在這一塊沒有文檔說明,用戶需要對(duì)對(duì)象自己進(jìn)行詳細(xì)的管理。當(dāng)調(diào)用sqlSession.commit()方法時(shí)才會(huì)進(jìn)行真正的提交。
抓取策略
Hibernate對(duì)實(shí)體關(guān)聯(lián)對(duì)象的抓取有著良好的機(jī)制。對(duì)于每一個(gè)關(guān)聯(lián)關(guān)系都可以詳細(xì)地設(shè)置是否延遲加載,并且提供關(guān)聯(lián)抓取、查詢抓取、子查詢抓取、批量抓取四種模式。 它是詳細(xì)配置和處理的。
而Mybatis的延遲加載是全局配置的,在resultMap中使用association中的select指定延遲加載去執(zhí)行的statement的id。
<!– 延遲加載的resultMap –> <resultMap type=”cn.itcast.mybatis.po.Orders” id=”OrdersUserLazyLoadingResultMap”> <!–對(duì)訂單信息進(jìn)行映射配置 –> <id column=”id” property=”id”/> <result column=”user_id” property=”userId”/> <result column=”number” property=”number”/> <result column=”createtime” property=”createtime”/> <result column=”note” property=”note”/> <association property=”user” javaType=”cn.itcast.mybatis.po.User” select=”cn.itcast.mybatis.mapper.UserMapper.findUserById” column=”user_id”> <!– 實(shí)現(xiàn)對(duì)用戶信息進(jìn)行延遲加載 –> </association> </resultMap>1.12. Hibernate 和 MyBatis 在緩存機(jī)制的不同
Hibernate緩存
Hibernate一級(jí)緩存是Session緩存,利用好一級(jí)緩存就需要對(duì)Session的生命周期進(jìn)行管理好。建議在一個(gè)Action**作中使用一個(gè)Session。一級(jí)緩存需要對(duì)Session進(jìn)行嚴(yán)格管理。
Hibernate二級(jí)緩存是SessionFactory級(jí)的緩存。 SessionFactory的緩存分為內(nèi)置緩存和外置緩存。內(nèi)置緩存中存放的是SessionFactory對(duì)象的一些**屬性包含的數(shù)據(jù)(映射元素?fù)?jù)及預(yù)定SQL語句等),對(duì)于應(yīng)用程序來說,它是只讀的。外置緩存中存放的是數(shù)據(jù)庫數(shù)據(jù)的副本,其作用和一級(jí)緩存類似.二級(jí)緩存除了以內(nèi)存作為存儲(chǔ)介質(zhì)外,還可以選用硬盤等外部存儲(chǔ)設(shè)備。二級(jí)緩存稱為進(jìn)程級(jí)緩存或SessionFactory級(jí)緩存,它可以被所有session共享,它的生命周期伴隨著SessionFactory的生命周期存在和消亡。
MyBatis緩存
MyBatis 包含一個(gè)非常強(qiáng)大的查詢緩存特性,它可以非常方便地配置和定制。MyBatis 3 中的緩存實(shí)現(xiàn)的很多改進(jìn)都已經(jīng)實(shí)現(xiàn)了,使得它更加強(qiáng)大而且易于配置。
一級(jí)緩存是SqlSession級(jí)別的緩存,二級(jí)緩存是mapper(命名空間)級(jí)別的緩存,默認(rèn)情況下是沒有開啟二級(jí)緩存的。
要開啟二級(jí)緩存,你需要在你的 SQL 映射文件中添加一行: <cache/>
字面上看就是這樣。這個(gè)簡單語句的效果如下:
映射語句文件中的所有 select 語句將會(huì)被緩存。
映射語句文件中的所有 insert,update 和 delete 語句會(huì)刷新緩存。
緩存會(huì)使用 Least Recently Used(LRU,最近最少使用的)算法來收回。
根據(jù)時(shí)間表(比如 no Flush Interval,沒有刷新間隔), 緩存不會(huì)以任何時(shí)間順序 來刷新。
緩存會(huì)存儲(chǔ)列表**或?qū)ο?無論查詢方法返回什么)的 1024 個(gè)引用。
緩存會(huì)被視為是 read/write(可讀/可寫)的緩存,意味著對(duì)象檢索不是共享的,而 且可以安全地被調(diào)用者修改,而不干擾其他調(diào)用者或線程所做的潛在修改。
所有的這些屬性都可以通過緩存元素的屬性來修改。
比如: <cache eviction=”FIFO” flushInterval=”60000″ size=”512″ readOnly=”true”/>
這個(gè)更高級(jí)的配置創(chuàng)建了一個(gè) FIFO 緩存,并每隔 60 秒刷新,存數(shù)結(jié)果對(duì)象或列表的 512 個(gè)引用,而且返回的對(duì)象被認(rèn)為是只讀的,因此在不同線程中的調(diào)用者之間修改它們會(huì) 導(dǎo)致沖突。可用的收回策略有, 默認(rèn)的是 LRU:
LRU – 最近最少使用的:移除最長時(shí)間不被使用的對(duì)象。
FIFO – 先進(jìn)先出:按對(duì)象進(jìn)入緩存的順序來移除它們。
SOFT – 軟引用:移除基于垃圾回收器狀態(tài)和軟引用規(guī)則的對(duì)象。
WEAK – 弱引用:更積極地移除基于垃圾收集器狀態(tài)和弱引用規(guī)則的對(duì)象。
flushInterval(刷新間隔)可以被設(shè)置為任意的正整數(shù),而且它們代表一個(gè)合理的毫秒 形式的時(shí)間段。默認(rèn)情況是不設(shè)置,也就是沒有刷新間隔,緩存僅僅調(diào)用語句時(shí)刷新。
size(引用數(shù)目)可以被設(shè)置為任意正整數(shù),要記住你緩存的對(duì)象數(shù)目和你運(yùn)行環(huán)境的 可用內(nèi)存資源數(shù)目。默認(rèn)值是1024。
readOnly(只讀)屬性可以被設(shè)置為 true 或 false。只讀的緩存會(huì)給所有調(diào)用者返回緩 存對(duì)象的相同實(shí)例。因此這些對(duì)象不能被修改。這提供了很重要的性能優(yōu)勢(shì)。可讀寫的緩存 會(huì)返回緩存對(duì)象的拷貝(通過序列化) 。這會(huì)慢一些,但是安全,因此默認(rèn)是 false。
相同點(diǎn)
Hibernate和Mybatis的二級(jí)緩存除了采用系統(tǒng)默認(rèn)的緩存機(jī)制外,都可以通過實(shí)現(xiàn)你自己的緩存或?yàn)槠渌谌骄彺娣桨?,?chuàng)建適配器來完全覆蓋緩存行為。
不同點(diǎn)
Hibernate的二級(jí)緩存配置在SessionFactory生成的配置文件中進(jìn)行詳細(xì)配置,然后再在具體的表-對(duì)象映射中配置是那種緩存。
MyBatis的二級(jí)緩存配置都是在每個(gè)具體的表-對(duì)象映射中進(jìn)行詳細(xì)配置,這樣針對(duì)不同的表可以自定義不同的緩存機(jī)制。并且Mybatis可以在命名空間**享相同的緩存配置和實(shí)例,通過Cache-ref來實(shí)現(xiàn)。
兩者比較
因?yàn)镠ibernate對(duì)查詢對(duì)象有著良好的管理機(jī)制,用戶無需關(guān)心SQL。所以在使用二級(jí)緩存時(shí)如果出現(xiàn)臟數(shù)據(jù),系統(tǒng)會(huì)報(bào)出錯(cuò)誤并提示。
而MyBatis在這一方面,使用二級(jí)緩存時(shí)需要特別小心。如果不能完全確定數(shù)據(jù)更新**作的波及范圍,避免Cache的盲目使用。否則,臟數(shù)據(jù)的出現(xiàn)會(huì)給系統(tǒng)的正常運(yùn)行帶來很大的隱患。
1.13. Hibernate 和 MyBatis 對(duì)比總結(jié)
兩者相同點(diǎn)
Hibernate與MyBatis都可以是通過SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory 生成Session,最后由Session來開啟執(zhí)行事務(wù)和SQL語句。其中SessionFactoryBuider,SessionFactory,Session的生命周期都是差不多的。
Hibernate和MyBatis都支持JDBC和JTA事務(wù)處理。
Mybatis優(yōu)勢(shì)
MyBatis可以進(jìn)行更為細(xì)致的SQL優(yōu)化,可以減少查詢字段。
MyBatis容易掌握,而Hibernate門檻較高。
Hibernate優(yōu)勢(shì)
Hibernate的DAO層開發(fā)比MyBatis簡單,Mybatis需要維護(hù)SQL和結(jié)果映射。
Hibernate對(duì)對(duì)象的維護(hù)和緩存要比MyBatis好,對(duì)增刪改查的對(duì)象的維護(hù)要方便。
Hibernate數(shù)據(jù)庫移植性很好,MyBatis的數(shù)據(jù)庫移植性不好,不同的數(shù)據(jù)庫需要寫不同SQL。
Hibernate有更好的二級(jí)緩存機(jī)制,可以使用第三方緩存。MyBatis本身提供的緩存機(jī)制不佳,更新**作不能指定刷新指定記錄,會(huì)清空整個(gè)表,但是也可以使用第三方緩存。
Hibernate 封裝性好,屏蔽了數(shù)據(jù)庫差異,自動(dòng)生成SQL語句,應(yīng)對(duì)數(shù)據(jù)庫變化能力較弱,SQL語句優(yōu)化困難。
MyBatis僅實(shí)現(xiàn)了SQL語句和對(duì)象的映射,需要針對(duì)具體的數(shù)據(jù)庫寫SQL語句,應(yīng)對(duì)數(shù)據(jù)庫變化能力較強(qiáng),SQL語句優(yōu)化較為方便。
1.14. SSH 和 S** 對(duì)比總結(jié)
SSH 和 S** 的技術(shù)框架的不同只需要比較Struts2和SpringMVC的不同,以及Hibernate和MyBatis的不同。
對(duì)于不同的功能,兩大技術(shù)陣營均有對(duì)應(yīng)的解決方案。SSH將配置文件開發(fā)用到極致。S**將注解開發(fā)用到極致。
企業(yè)進(jìn)行技術(shù)選型,以低成本**作為技術(shù)選型的原則,根據(jù)項(xiàng)目組的技術(shù)力量來進(jìn)行選擇。
小弟水平有限,只能總結(jié)到這里。更進(jìn)一步的底層代碼級(jí)別的對(duì)比,才是本質(zhì)的區(qū)別。用法上的區(qū)別只是表象而已,但是對(duì)于廣大開發(fā)者來說,誰的開發(fā)者用戶體驗(yàn)好,顯然更能贏得開發(fā)者的青睞。
關(guān)于聯(lián)想t430s筆記本是哪一年出的,聯(lián)想t430s筆記本配置到此分享完畢,希望能幫助到您。
原創(chuàng)文章,作者:Admin,如若轉(zhuǎn)載,請(qǐng)注明出處:http:///196859.html