他看了這篇SpringMVC,兩天上手開(kāi)發(fā)了

一涡戳、什么是SpringMVC?

SpringMVC是Spring家族的一員,Spring是將現(xiàn)在開(kāi)發(fā)中流行的組件進(jìn)行組合而成的一個(gè)框架挤庇!它用在基于MVC的表現(xiàn)層開(kāi)發(fā)拐格,類似于struts2框架

二墩新、為什么要使用SpringMVC马澈?

我們?cè)谥耙呀?jīng)學(xué)過(guò)了Struts2這么一個(gè)基于MVC的框架…那么我們已經(jīng)學(xué)會(huì)了Struts2瓢省,為啥要要學(xué)習(xí)SpringMVC呢?痊班??

下面我們來(lái)看一下Struts2不足之處:

有漏洞【詳細(xì)可以去搜索】

運(yùn)行速度較慢【比SpringMVC要慢】

配置的內(nèi)容較多【需要使用Struts.xml文件】

比較重量級(jí)

基于這么一些原因摹量,并且業(yè)內(nèi)現(xiàn)在SpringMVC已經(jīng)逐漸把Struts2給替代了…因此我們學(xué)習(xí)SpringMVC一方面能夠讓我們跟上業(yè)界的潮流框架涤伐,一方面SpringMVC確實(shí)是非常好用!

可以這么說(shuō)凝果,Struts2能做的東西睦尽,SpringMVC也能夠做

三、回顧Struts2開(kāi)發(fā)

如果沒(méi)接觸過(guò)Struts2的当凡,這里可以跳過(guò)。Struts2可以不學(xué)

在Struts2中沿量,我們的開(kāi)發(fā)特點(diǎn)是這樣的:

Action類繼承著ActionSupport類【如果要使用Struts2提供的額外功能,就要繼承它】

Action業(yè)務(wù)方法總是返回一個(gè)字符串朴则,再由Struts2內(nèi)部通過(guò)我們手寫的Struts.xml配置文件去跳轉(zhuǎn)到對(duì)應(yīng)的view

Action類是多例的权纤,接收Web傳遞過(guò)來(lái)的參數(shù)需要使用實(shí)例變量來(lái)記住,通常我們都會(huì)寫上set和get方法

四外邓、Struts2的工作流程

Struts2接收到request請(qǐng)求

將請(qǐng)求轉(zhuǎn)向我們的過(guò)濾分批器進(jìn)行過(guò)濾

讀取Struts2對(duì)應(yīng)的配置文件

經(jīng)過(guò)默認(rèn)的攔截器之后創(chuàng)建對(duì)應(yīng)的Action【多例】

執(zhí)行完業(yè)務(wù)方法就返回給response對(duì)象

五坐榆、SpringMVC快速入門

5.1導(dǎo)入開(kāi)發(fā)包

如果用Maven的冗茸,那導(dǎo)入Maven依賴即可

前6個(gè)是Spring的核心功能包【IOC】夏漱,第7個(gè)是關(guān)于web的包,第8個(gè)是SpringMVC包

org.springframework.context-3.0.5.RELEASE.jar

org.springframework.expression-3.0.5.RELEASE.jar

org.springframework.core-3.0.5.RELEASE.jar

org.springframework.beans-3.0.5.RELEASE.jar

org.springframework.asm-3.0.5.RELEASE.jar

commons-logging.jar

org.springframework.web-3.0.5.RELEASE.jar

org.springframework.web.servlet-3.0.5.RELEASE.jar

5.2編寫Action

Action實(shí)現(xiàn)Controller接口

public class HelloAction implements Controller {

@Override

public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {

return null;

}

}

我們只要實(shí)現(xiàn)handleRequest方法即可屎篱,該方法已經(jīng)說(shuō)了request和response對(duì)象給我們用了交播。這是我們非常熟悉的request和response對(duì)象践付。然而該方法返回的是ModelAndView這么一個(gè)對(duì)象永高,這是和Struts2不同的。Struts2返回的是字符串命爬,而SpringMVC返回的是ModelAndView

ModelAndView其實(shí)他就是將我們的視圖路徑和數(shù)據(jù)封裝起來(lái)而已【我們想要跳轉(zhuǎn)到哪曹傀,把什么數(shù)據(jù)存到request域中皆愉,設(shè)置這個(gè)對(duì)象的屬性就行了】幕庐。

public class HelloAction implements Controller {

@Override

public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {

ModelAndView modelAndView = new ModelAndView();

//跳轉(zhuǎn)到hello.jsp頁(yè)面翔脱。

modelAndView.setViewName("/hello.jsp");

return modelAndView;

}

}

5.3注冊(cè)核心控制器

在Struts2中媒鼓,我們想要使用Struts2的功能,那么就得在web.xml文件中配置過(guò)濾器暂氯。而我們使用SpringMVC的話亮蛔,我們是在web.xml中配置核心控制器

DispatcherServlet

org.springframework.web.servlet.DispatcherServlet

contextConfigLocation

classpath:hello.xml

DispatcherServlet

*.action

5.4創(chuàng)建SpringMVC控制器

我們?cè)趆ello.xml配置文件中把SpringMVC的控制器創(chuàng)建出來(lái)

注冊(cè)控制器

name屬性的值表示的是請(qǐng)求的路徑【也就是說(shuō)究流,當(dāng)用戶請(qǐng)求到/helloAction時(shí)芬探,就交由HelloAction類進(jìn)行處理】

5.5訪問(wèn)

當(dāng)我們?cè)跒g覽器訪問(wèn)http://localhost:8080/hello.action的時(shí)候偷仿,Spring會(huì)讀取到我們的訪問(wèn)路徑,然后對(duì)比一下我們的配置文件中是否有配置/hello.action节榜,如果有宗苍。那么就交由對(duì)應(yīng)的Action類來(lái)進(jìn)行處理浓若。Action類的業(yè)務(wù)方法將其請(qǐng)求輸出到hello.jsp頁(yè)面上蛇数。

六耳舅、SpringMVC工作流程

這里給你們文字描述一下:

用戶發(fā)送請(qǐng)求

請(qǐng)求交由核心控制器處理

核心控制器找到映射器浦徊,映射器看看請(qǐng)求路徑是什么

核心控制器再找到適配器盔性,看看有哪些類實(shí)現(xiàn)了Controller接口或者對(duì)應(yīng)的bean對(duì)象

將帶過(guò)來(lái)的數(shù)據(jù)進(jìn)行轉(zhuǎn)換冕香,格式化等等操作

找到我們的控制器Action悉尾,處理完業(yè)務(wù)之后返回一個(gè)ModelAndView對(duì)象

最后通過(guò)視圖解析器來(lái)對(duì)ModelAndView進(jìn)行解析

跳轉(zhuǎn)到對(duì)應(yīng)的JSP/html頁(yè)面

上面的工作流程中,我們是沒(méi)有講過(guò)映射器愕难,適配器猫缭,視圖解析器這樣的東西的猜丹。但是SpringMVC的環(huán)境還是被我們搭建起來(lái)了茫打。

下面就由我來(lái)一個(gè)一個(gè)來(lái)介紹他們是有什么用的老赤!

6.1映射器

我們?cè)趙eb.xml中配置規(guī)定只要是.action為后綴的請(qǐng)求都是會(huì)經(jīng)過(guò)SpringMVC的核心Servlet抬旺。

當(dāng)我們接收到請(qǐng)求的時(shí)候开财,我們發(fā)現(xiàn)是hello.action,是會(huì)經(jīng)過(guò)我們的核心Servlet的碾褂,那么核心Servlet就會(huì)去找有沒(méi)有專門的Action類來(lái)處理hello.action請(qǐng)求的正塌。

也就是說(shuō):映射器就是用于處理“什么樣的請(qǐng)求提交給Action”處理乓诽○欤【默認(rèn)可省略的】…

其實(shí)我們?cè)诳焖偃腴T的例子已經(jīng)配置了:name屬性就是規(guī)定了hello.action到HelloAction控制器中處理帐姻!

注冊(cè)控制器

name屬性的值表示的是請(qǐng)求的路徑【也就是說(shuō),當(dāng)用戶請(qǐng)求到/helloAction時(shí)忧饭,就交由HelloAction類進(jìn)行處理】

映射器默認(rèn)的值是這樣的:

當(dāng)然了词裤,上面我們?cè)趧?chuàng)建控制器的時(shí)候【也就是HelloAction】可以不使用name屬性來(lái)指定路徑吼砂,可以使用我們的映射器來(lái)配置渔肩。如以下的代碼:

當(dāng)我們需要多個(gè)請(qǐng)求路徑都交由helloAction控制器來(lái)處理的話拇惋,我們只要添加prop標(biāo)簽就行了撑帖!

6.2適配器

當(dāng)我們映射器找到對(duì)應(yīng)的Action來(lái)處理請(qǐng)求的時(shí)候胡嘿,核心控制器會(huì)讓適配器去找該類是否實(shí)現(xiàn)了Controller接口衷敌〗陕蓿【默認(rèn)可省略的】

也就是說(shuō):適配器就是去找實(shí)現(xiàn)了Controller接口的類


6.3視圖解析器

我們把結(jié)果封裝到ModelAndView以后面氓,SpringMVC會(huì)使用視圖解析器來(lái)對(duì)ModelAndView進(jìn)行解析侧但。

【默認(rèn)可省略的】

也有一種情況是不能省略的航罗。我們?cè)诳焖偃腴T的例子中粥血,將結(jié)果封裝到ModelAndView中,用的是絕對(duì)真實(shí)路徑缭嫡!如果我們用的是邏輯路徑妇蛀,那么就必須對(duì)其配置评架,否則SpringMVC是找不到對(duì)應(yīng)的路徑的炕泳。

那什么是邏輯路徑呢培遵?籽腕?节仿?我們?cè)赟truts2中廊宪,返回的是"success"這樣的字符串箭启,從而跳轉(zhuǎn)到success.jsp這樣的頁(yè)面上傅寡。我們就可以把"success"稱作為邏輯路徑。

在Action中返回hello芜抒,hello是一個(gè)邏輯路徑宅倒。需要我們使用視圖解析器把邏輯路基補(bǔ)全

public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {

ModelAndView modelAndView = new ModelAndView();

//跳轉(zhuǎn)到hello.jsp頁(yè)面拐迁。

modelAndView.setViewName("hello");

return modelAndView;

}

如果不使用視圖解析器的話线召,那么就會(huì)找不到頁(yè)面:

因此缓淹,我們需要配置視圖解析器

如果Action中書寫的是視圖邏輯名稱割卖,那么視圖解析器就必須配置

如果Action中書寫的是視圖真實(shí)名稱鹏溯,那么視圖解析器就可選配置

七丙挽、AbstractCommandController

到目前為止颜阐,我們都沒(méi)有將SpringMVC是怎么接收web端傳遞過(guò)來(lái)的參數(shù)的凳怨。

我們?cè)赟truts2中肤舞,只要在Action類上寫對(duì)應(yīng)的成員變量李剖,給出對(duì)應(yīng)的set和get方法篙顺。那么Struts2就會(huì)幫我們把參數(shù)封裝到對(duì)應(yīng)的成員變量中德玫,是非常方便的宰僧。

那么我們?cè)赟pringMVC中是怎么獲取參數(shù)的呢?查刻?穗泵?佃延?我們是將Action繼承AbstractCommandController這么一個(gè)類的履肃。

public class HelloAction extends AbstractCommandController {

@Override

protected ModelAndView handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, BindException e) throws Exception {

return null;

}

}

在講解該控制器之前尺棋,首先我們要明白SpringMVC控制器一個(gè)與Struts2不同的地方:SpringMVC的控制器是單例的膘螟,Struts2的控制器是多例的荆残!

也就是說(shuō):Struts2收集變量是定義成員變量來(lái)進(jìn)行接收内斯,而SpringMVC作為單例的俘闯,是不可能使用成員變量來(lái)進(jìn)行接收的【因?yàn)闀?huì)有多個(gè)用戶訪問(wèn)备徐,就會(huì)出現(xiàn)數(shù)據(jù)不合理性】蜜猾!

那么SpringMVC作為單例的蹭睡,他只能通過(guò)方法的參數(shù)來(lái)進(jìn)行接收對(duì)應(yīng)的參數(shù)肩豁!只有方法才能保證不同的用戶對(duì)應(yīng)不同的數(shù)據(jù)清钥!

7.1實(shí)體

實(shí)體的屬性要和web頁(yè)面上的name提交過(guò)來(lái)的名稱是一致的祟昭。這和Struts2是一樣的篡悟!

public class User {

private String id;

private String username;

public User() {

}

public User(String id, String username) {

this.id = id;

this.username = username;

}

public String getId() {

return id;

}

public void setId(String id) {

this.id = id;

}

public String getUsername() {

return username;

}

public void setUsername(String username) {

this.username = username;

}

@Override

public String toString() {

return "User{" +

"id='" + id + '\'' +

", username='" + username + '\'' +

'}';

}

}

7.2提交參數(shù)的JSP

<form action="${pageContext.request.contextPath}/hello.action" method="post">

<table align="center">

<tr>

<td>用戶名:</td>

<td><input type="text" name="username"></td>

</tr>

<tr>

<td>編號(hào)</td>

<td><input type="text" name="id"></td>

</tr>

<tr>

<td colspan="2">

<input type="submit" value="提交">

</td>

</tr>

</table>

</form>

7.3 配置Action處理請(qǐng)求

<bean class="HelloAction" id="helloAction"></bean>

<!-- 注冊(cè)映射器(handler包)(框架) -->

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

<property name="mappings">

<props>

<prop key="/hello.action">helloAction</prop>

</props>

</property>

</bean>

7.4 Action接收參數(shù)

public class HelloAction extends AbstractCommandController {

/*設(shè)置無(wú)參構(gòu)造器荷腊,里邊調(diào)用setCommandClass方法女仰,傳入要封裝的對(duì)象*/

public HelloAction() {

this.setCommandClass(User.class);

}

/**

*

* @param httpServletRequest

* @param httpServletResponse

* @param o 這里的對(duì)象就表示已經(jīng)封裝好的了User對(duì)象了董栽。锭碳!

* @param e

* @return

* @throws Exception

*/

@Override

protected ModelAndView handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, BindException e) throws Exception {

User user = (User) o;

System.out.println(user);

ModelAndView modelAndView = new ModelAndView();

//跳轉(zhuǎn)到ok.jsp

modelAndView.setViewName("/WEB-INF/ok.jsp");

//將數(shù)據(jù)封裝到ModelAndView中

modelAndView.addObject("USER", user);

return modelAndView;

}

}

7.5測(cè)試效果:

八、小總結(jié)

Struts2和SpringMVC存值的區(qū)別:

SpringMVC的工作流程:

用戶發(fā)送HTTP請(qǐng)求,SpringMVC核心控制器接收到請(qǐng)求

找到映射器看該請(qǐng)求是否交由對(duì)應(yīng)的Action類進(jìn)行處理

找到適配器看有無(wú)該Action類

Action類處理完結(jié)果封裝到ModelAndView中

通過(guò)視圖解析器把數(shù)據(jù)解析诊胞,跳轉(zhuǎn)到對(duì)應(yīng)的JSP頁(yè)面

控制器

AbstractCommandController

可以實(shí)現(xiàn)對(duì)參數(shù)數(shù)據(jù)的封裝

參數(shù)綁定撵孤、數(shù)據(jù)回顯邪码、文件上傳

本文主要講解的知識(shí)點(diǎn)如下:

參數(shù)綁定

數(shù)據(jù)回顯

文件上傳

一闭专、參數(shù)綁定

我們?cè)贑ontroller使用方法參數(shù)接收值影钉,就是把web端的值給接收到Controller中處理,這個(gè)過(guò)程就叫做參數(shù)綁定…

1.1默認(rèn)支持的參數(shù)類型

從上面的用法我們可以發(fā)現(xiàn)斧拍,我們可以使用request對(duì)象肆汹、Model對(duì)象等等昂勉,其實(shí)是不是可以隨便把參數(shù)寫上去都行岗照?攒至?迫吐?其實(shí)并不是的…

Controller方法默認(rèn)支持的參數(shù)類型有4個(gè),這4個(gè)足以支撐我們的日常開(kāi)發(fā)了

HttpServletRequest

HttpServletResponse

HttpSession

Model

1.2參數(shù)的綁定過(guò)程

一般地鳖擒,我們要用到自定義的參數(shù)綁定就是上面所講的日期類型轉(zhuǎn)換以及一些特殊的需求…對(duì)于平常的參數(shù)綁定蒋荚,我們是無(wú)需使用轉(zhuǎn)換器的惊奇,SpringMVC就已經(jīng)幫我們干了這個(gè)活了…

1.3自定義綁定參數(shù)【老方式赊时、全部Action均可使用】

在上一篇我們已經(jīng)簡(jiǎn)單介紹了怎么把字符串轉(zhuǎn)換成日期類型了【使用的是WebDataBinder方式】…其實(shí)那是一個(gè)比較老的方法祖秒,我們可以使用SpringMVC更推薦的方式…

在上次把字符串轉(zhuǎn)換成日期類型竭缝,如果使用的是WebDataBinder方式的話抬纸,那么該轉(zhuǎn)換僅僅只能在當(dāng)前Controller使用…如果想要全部的Controller都能夠使用,那么我們可以使用WebBindingInitializer方式

如果想多個(gè)controller需要共同注冊(cè)相同的屬性編輯器湿故,可以實(shí)現(xiàn)PropertyEditorRegistrar接口阿趁,并注入webBindingInitializer中。

實(shí)現(xiàn)接口

public class CustomPropertyEditor implements PropertyEditorRegistrar {

@Override

public void registerCustomEditors(PropertyEditorRegistry binder) {

binder.registerCustomEditor(Date.class, new CustomDateEditor(

new SimpleDateFormat("yyyy-MM-dd HH-mm-ss"), true));

}

}

1.4配置轉(zhuǎn)換器

注入到webBindingInitializer中

<!-- 注冊(cè)屬性編輯器 -->

<bean id="customPropertyEditor" class="cn.itcast.ssm.controller.propertyeditor.CustomPropertyEditor"></bean>

<!-- 自定義webBinder -->

<bean id="customBinder"

class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">

<!-- propertyEditorRegistrars用于屬性編輯器 -->

<property name="propertyEditorRegistrars">

<list>

<ref bean="customPropertyEditor" />

</list>

</property>

</bean>

<!-- 注解適配器 -->

<bean

class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">

<!-- 在webBindingInitializer中注入自定義屬性編輯器坛猪、自定義轉(zhuǎn)換器 -->

<property name="webBindingInitializer" ref="customBinder"></property>

</bean

1.5 自定義參數(shù)轉(zhuǎn)換器【新方式脖阵、推崇方式】

上面的方式是對(duì)象較老的,現(xiàn)在我們一般都是實(shí)現(xiàn)Converter接口來(lái)實(shí)現(xiàn)自定義參數(shù)轉(zhuǎn)換…我們就來(lái)看看實(shí)現(xiàn)Converter比上面有什么好

配置日期轉(zhuǎn)換器

public class CustomDateConverter implements Converter {

@Override

public Date convert(String source) {

try {

//進(jìn)行日期轉(zhuǎn)換

return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(source);

} catch (Exception e) {

e.printStackTrace();

}

return null;

}

}

配置去除字符串轉(zhuǎn)換器

public class StringTrimConverter implements Converter {

@Override

public String convert(String source) {

try {

//去掉字符串兩邊空格墅茉,如果去除后為空設(shè)置為null

if(source!=null){

source = source.trim();

if(source.equals("")){

return null;

}

}

} catch (Exception e) {

e.printStackTrace();

}

return source;

}

}

從上面可以得出,我們想要轉(zhuǎn)換什么內(nèi)容就斤,就直接實(shí)現(xiàn)接口悍募,該接口又是支持泛型的,閱讀起來(lái)就非常方便了…

1.6 配置轉(zhuǎn)換器

<!-- 轉(zhuǎn)換器 -->

<bean id="conversionService"

class="org.springframework.format.support.FormattingConversionServiceFactoryBean">

<property name="converters">

<list>

<bean class="cn.itcast.ssm.controller.converter.CustomDateConverter"/>

<bean class="cn.itcast.ssm.controller.converter.StringTrimConverter"/>

</list>

</property>

</bean>

<!-- 自定義webBinder -->

<bean id="customBinder"

class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">

<!-- 使用converter進(jìn)行參數(shù)轉(zhuǎn) -->

<property name="conversionService" ref="conversionService" />

</bean>

<!-- 注解適配器 -->

<bean

class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">

<!-- 在webBindingInitializer中注入自定義屬性編輯器洋机、自定義轉(zhuǎn)換器 -->

<property name="webBindingInitializer" ref="customBinder"></property>

</bean>

如果是基于<mvc:annotation-driven>的話坠宴,我們是這樣配置的

<mvc:annotation-driven conversion-service="conversionService">

</mvc:annotation-driven>

<!-- conversionService -->

<bean id="conversionService"

class="org.springframework.format.support.FormattingConversionServiceFactoryBean">

<!-- 轉(zhuǎn)換器 -->

<property name="converters">

<list>

<bean class="cn.itcast.ssm.controller.converter.CustomDateConverter"/>

<bean class="cn.itcast.ssm.controller.converter.StringTrimConverter"/>

</list>

</property>

</bean>

1.7 @RequestParam注解

我們一般使用的參數(shù)綁定都有遵循的規(guī)則:方法參數(shù)名要與傳遞過(guò)來(lái)的name屬性名相同。

在默認(rèn)的情況下槐秧,只有名字相同啄踊,SpringMVC才會(huì)幫我們進(jìn)行參數(shù)綁定…

如果我們使用@RequestParam注解的話,我們就可以使方法參數(shù)名與傳遞過(guò)來(lái)的name屬性名不同…

該注解有三個(gè)變量

value【指定name屬性的名稱是什么】

required【是否必須要有該參數(shù)】

defaultvalue設(shè)置默認(rèn)值

例子:我們的方法參數(shù)叫id刁标,而頁(yè)面帶過(guò)來(lái)的name屬性名字叫item_id颠通,一定需要該參數(shù)

public String editItem(@RequestParam(value="item_id",required=true) String id) {

}

1.8 Controller方法返回值

Controller方法的返回值其實(shí)就幾種類型,我們來(lái)總結(jié)一下…

void

String

ModelAndView

redirect重定向

forward轉(zhuǎn)發(fā)

二膀懈、數(shù)據(jù)回顯

其實(shí)數(shù)據(jù)回顯我們現(xiàn)在的話就一點(diǎn)也不陌生了…我們剛使用EL表達(dá)式的時(shí)候就已經(jīng)學(xué)會(huì)了數(shù)據(jù)回顯了顿锰,做SSH項(xiàng)目的時(shí)候也有三圈問(wèn)題的數(shù)據(jù)回顯…

在頁(yè)面上數(shù)據(jù)回顯本質(zhì)上就是獲取reqeust域的值…

而在我們SpringMVC中,我們是使用Model來(lái)把數(shù)據(jù)綁定request域?qū)ο笾械?/b>

一般地我們都是使用model.addAttribute()的方式把數(shù)據(jù)綁定到request域?qū)ο笾小鋵?shí)SpringMVC還支持注解的方式

2.1@ModelAttribute注解

我們可以將請(qǐng)求的參數(shù)放到Model中启搂,回顯到頁(yè)面上

上面這種用法和model.addAttribute()的方式是沒(méi)啥區(qū)別的硼控,也體現(xiàn)不了注解的方便性…

而如果我們要回顯的數(shù)據(jù)是公共的話,那么我們就能夠體會(huì)到注解的方便性了胳赌,我們把公共需要顯示的屬性抽取成方法牢撼,將返回值返回就行了。

那我們就不用在每一個(gè)controller方法通過(guò)Model將數(shù)據(jù)傳到頁(yè)面疑苫。

三熏版、SpringMVC文件上傳

我們使用Struts2的時(shí)候纷责,覺(jué)得Struts2的文件上傳方式比傳統(tǒng)的文件上傳方式好用多了…

既然我們正在學(xué)習(xí)SpringMVC,那么我們也看一下SpringMVC究竟是怎么上傳文件的…

3.1配置虛擬目錄

在這次撼短,我們并不是把圖片上傳到我們的工程目錄中…

那為啥不將圖片直接上傳到我們的工程目錄中呢再膳??曲横?我們仔細(xì)想想喂柒,按照我們之前的做法,直接把文件上傳到工程目錄禾嫉,而我們的工程目錄是我們寫代碼的地方?…往往我們需要備份我們的工程目錄灾杰。

如果把圖片都上傳到工程目錄中,那么就非常難以處理圖片了…

因此熙参,我們需要配置Tomcat的虛擬目錄來(lái)解決吭露,把上傳的文件放在虛擬目錄上

又值得注意的是,Idea使用的Tomcat并不能使用傳統(tǒng)的配置方式尊惰,也就是修改server.xml方式來(lái)配置虛擬目錄,在Idea下好像不支持這種做法…

有興趣的小伙伴可以去測(cè)試一下:

http://blog.csdn.net/hon_3y/article/details/54412484

那么我在網(wǎng)上已經(jīng)找到了對(duì)應(yīng)的解決辦法泥兰,就是如果在idea上配置虛擬目錄

http://blog.csdn.net/LABLENET/article/details/51160828

檢測(cè)是否配置成功:

3.2快速入門

在SpringMVC中文件上傳需要用到的jar包

如果用Maven的小伙伴弄屡,引入pom就好了

commons-fileupload-1.2.2.jar

commons-io-2.4.jar

配置文件上傳解析器

<!-- 文件上傳 -->

<bean id="multipartResolver"

class="org.springframework.web.multipart.commons.CommonsMultipartResolver">

<!-- 設(shè)置上傳文件的最大尺寸為5MB -->

<property name="maxUploadSize">

<value>5242880</value>

</property>

</bean>

測(cè)試的JSP

<%--

Created by IntelliJ IDEA.

User: ozc

Date: 2017/8/11

Time: 9:56

To change this template use File | Settings | File Templates.

--%>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>

<head>

<title>測(cè)試文件上傳</title>

</head>

<body>

<form action="${pageContext.request.contextPath}/upload.action" method="post" enctype="multipart/form-data" >

<input type="file" name="picture">

<input type="submit" value="submit">

</form>

</body>

</html>

值得注意的是,在JSP的name屬性寫的是picture鞋诗,那么在Controller方法參數(shù)的名稱也是要寫picture的膀捷,否則是獲取不到對(duì)應(yīng)的文件的…

@Controller

public class UploadController {

@RequestMapping("/upload")

//MultipartFile該對(duì)象就是封裝了圖片文件

public void upload(MultipartFile picture) throws Exception {

System.out.println(picture.getOriginalFilename());

}

}

四、總結(jié)

在SpringMVC中的業(yè)務(wù)方法默認(rèn)支持的參數(shù)有四種

request

response

session

model

我們的參數(shù)綁定(自動(dòng)封裝參數(shù))是由我們的轉(zhuǎn)換器來(lái)進(jìn)行綁定的∠鞅颍現(xiàn)在用的一般都是Converter轉(zhuǎn)換器

在上一章中我們使用WebDataBinder方式來(lái)實(shí)現(xiàn)對(duì)日期格式的轉(zhuǎn)化全庸,當(dāng)時(shí)僅僅是可用于當(dāng)前Action的。我們想要讓全部Action都可以使用的話融痛,有兩種方式:

實(shí)現(xiàn)PropertyEditorRegistrar(比較老的方式)

實(shí)現(xiàn)Converter(新的方式)

參數(shù)綁定都有遵循的規(guī)則:方法參數(shù)名要與傳遞過(guò)來(lái)的name屬性名相同

我們可以使用@RequestParam注解來(lái)具體指定對(duì)應(yīng)的name屬性名稱壶笼,這樣也是可以實(shí)現(xiàn)參數(shù)綁定的。

還能夠配置該參數(shù)是否是必須的雁刷。

Controller方法的返回值有5種:

void

String

ModelAndView

redirect重定向

forward轉(zhuǎn)發(fā)

Model內(nèi)部就是將數(shù)據(jù)綁定到request域?qū)ο笾械摹?/p>

@ModelAttribute注解能夠?qū)?shù)據(jù)綁定到model中(也就是request中)覆劈,如果經(jīng)常需要綁定到model中的數(shù)據(jù),抽取成方法來(lái)使用這個(gè)注解還是不錯(cuò)的沛励。

idea配置虛擬目其實(shí)就是加多一個(gè)deployment责语,然后配置它的應(yīng)用路徑

SpringMVC的文件上傳就是配置一個(gè)上傳解析器,使用MultipartFile來(lái)接收帶過(guò)來(lái)的文件目派。

攔截器坤候、統(tǒng)一處理異常、RESTful企蹭、攔截器

本文主要講解的知識(shí)點(diǎn)如下:

校驗(yàn)器

統(tǒng)一處理異常

RESTful

攔截器

一白筹、Validation

在我們的Struts2中智末,我們是繼承ActionSupport來(lái)實(shí)現(xiàn)校驗(yàn)的…它有兩種方式來(lái)實(shí)現(xiàn)校驗(yàn)的功能

手寫代碼

XML配置

這兩種方式也是可以特定處理方法或者整個(gè)Action的

而SpringMVC使用JSR-303(javaEE6規(guī)范的一部分)校驗(yàn)規(guī)范,springmvc使用的是Hibernate Validator(和Hibernate的ORM無(wú)關(guān))

1.1快速入門

導(dǎo)入jar包

配置校驗(yàn)器

<!-- 校驗(yàn)器 -->

<bean id="validator"

class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">

<!-- 校驗(yàn)器 -->

<property name="providerClass" value="org.hibernate.validator.HibernateValidator" />

<!-- 指定校驗(yàn)使用的資源文件遍蟋,如果不指定則默認(rèn)使用classpath下的ValidationMessages.properties -->

<property name="validationMessageSource" ref="messageSource" />

錯(cuò)誤信息的校驗(yàn)文件配置

<!-- 校驗(yàn)錯(cuò)誤信息配置文件 -->

<bean id="messageSource"

class="org.springframework.context.support.ReloadableResourceBundleMessageSource">

<!-- 資源文件名 -->

<property name="basenames">

<list>

<value>classpath:CustomValidationMessages</value>

</list>

</property>

<!-- 資源文件編碼格式 -->

<property name="fileEncodings" value="utf-8" />

<!-- 對(duì)資源文件內(nèi)容緩存時(shí)間吹害,單位秒 -->

<property name="cacheSeconds" value="120" />

</bean>

添加到自定義參數(shù)綁定的WebBindingInitializer中

<!-- 自定義webBinder -->

<bean id="customBinder"

class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">

<!-- 配置validator -->

<property name="validator" ref="validator" />

</bean>

最終添加到適配器中

<!-- 注解適配器 -->

<bean

class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">

<!-- 在webBindingInitializer中注入自定義屬性編輯器、自定義轉(zhuǎn)換器 -->

<property name="webBindingInitializer" ref="customBinder"></property>

</bean>

創(chuàng)建CustomValidationMessages配置文件

定義規(guī)則

package entity;

import javax.validation.constraints.NotNull;

import javax.validation.constraints.Size;

import java.util.Date;

public class Items {

private Integer id;

//商品名稱的長(zhǎng)度請(qǐng)限制在1到30個(gè)字符

@Size(min=1,max=30,message="{items.name.length.error}")

private String name;

private Float price;

private String pic;

//請(qǐng)輸入商品生產(chǎn)日期

@NotNull(message="{items.createtime.is.notnull}")

private Date createtime;

private String detail;

public Integer getId() {

return id;

}

public void setId(Integer id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name == null ? null : name.trim();

}

public Float getPrice() {

return price;

}

public void setPrice(Float price) {

this.price = price;

}

public String getPic() {

return pic;

}

public void setPic(String pic) {

this.pic = pic == null ? null : pic.trim();

}

public Date getCreatetime() {

return createtime;

}

public void setCreatetime(Date createtime) {

this.createtime = createtime;

}

public String getDetail() {

return detail;

}

public void setDetail(String detail) {

this.detail = detail == null ? null : detail.trim();

}

}

測(cè)試:

<%--

Created by IntelliJ IDEA.

User: ozc

Date: 2017/8/11

Time: 9:56

To change this template use File | Settings | File Templates.

--%>

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>

<head>

<title>測(cè)試文件上傳</title>

</head>

<body>

<form action="${pageContext.request.contextPath}/validation.action" method="post" >

名稱:<input type="text" name="name">

日期:<input type="text" name="createtime">

<input type="submit" value="submit">

</form>

</body>

</html>

Controller需要在校驗(yàn)的參數(shù)上添加@Validation注解…拿到BindingResult對(duì)象…

@RequestMapping("/validation")

public void validation(@Validated Items items, BindingResult bindingResult) {

List allErrors = bindingResult.getAllErrors();

for (ObjectError allError : allErrors) {

System.out.println(allError.getDefaultMessage());

}

}

由于我在測(cè)試的時(shí)候虚青,已經(jīng)把日期轉(zhuǎn)換器關(guān)掉了它呀,因此提示了字符串不能轉(zhuǎn)換成日期,但是名稱的校驗(yàn)已經(jīng)是出來(lái)了…

1.2分組校驗(yàn)

分組校驗(yàn)其實(shí)就是為了我們的校驗(yàn)更加靈活棒厘,有的時(shí)候纵穿,我們并不需要把我們當(dāng)前配置的屬性都進(jìn)行校驗(yàn),而需要的是當(dāng)前的方法僅僅校驗(yàn)?zāi)承┑膶傩浴?/b>那么此時(shí)奢人,我們就可以用到分組校驗(yàn)了…

步驟:

定義分組的接口【主要是標(biāo)識(shí)】

定于校驗(yàn)規(guī)則屬于哪一個(gè)組

在Controller方法中定義使用校驗(yàn)分組

二谓媒、統(tǒng)一異常處理

在我們之前SSH,使用Struts2的時(shí)候也配置過(guò)統(tǒng)一處理異澈魏酰…

當(dāng)時(shí)候是這么干的:

在service層中自定義異常

在action層也自定義異常

對(duì)于Dao層的異常我們先不管【因?yàn)槲覀児懿恢涔撸琩ao層的異常太致命了】

service層拋出異常,Action把service層的異常接住支救,通過(guò)service拋出的異常來(lái)判斷是否讓請(qǐng)求通過(guò)

如果不通過(guò)抢野,那么接著拋出Action異常

在Struts的配置文件中定義全局視圖,頁(yè)面顯示錯(cuò)誤信息

詳情可看:http://blog.csdn.net/hon_3y/article/details/72772559

那么我們這次的統(tǒng)一處理異常的方案是什么呢各墨?指孤??贬堵?

我們知道Java中的異呈研可以分為兩類

編譯時(shí)期異常

運(yùn)行期異常

對(duì)于運(yùn)行期異常我們是無(wú)法掌控的,只能通過(guò)代碼質(zhì)量黎做、在系統(tǒng)測(cè)試時(shí)詳細(xì)測(cè)試等排除運(yùn)行時(shí)異常

而對(duì)于編譯時(shí)期的異常叉跛,我們可以在代碼手動(dòng)處理異常可以try/catch捕獲引几,可以向上拋出昧互。

我們可以換個(gè)思路,自定義一個(gè)模塊化的異常信息伟桅,比如:商品類別的異常

public class CustomException extends Exception {

//異常信息

private String message;

public CustomException(String message){

super(message);

this.message = message;

}

public String getMessage() {

return message;

}

public void setMessage(String message) {

this.message = message;

}

}

我們?cè)诓榭碨pring源碼的時(shí)候發(fā)現(xiàn):前端控制器DispatcherServlet在進(jìn)行HandlerMapping敞掘、調(diào)用HandlerAdapter執(zhí)行Handler過(guò)程中,如果遇到異常楣铁,在系統(tǒng)中自定義統(tǒng)一的異常處理器玖雁,寫系統(tǒng)自己的異常處理代碼。

我們也可以學(xué)著點(diǎn)盖腕,定義一個(gè)統(tǒng)一的處理器類來(lái)處理異澈斩…

2.1 定義統(tǒng)一異常處理器類

public class CustomExceptionResolver implements HandlerExceptionResolver? {

//前端控制器DispatcherServlet在進(jìn)行HandlerMapping浓镜、調(diào)用HandlerAdapter執(zhí)行Handler過(guò)程中,如果遇到異常就會(huì)執(zhí)行此方法

//handler最終要執(zhí)行的Handler劲厌,它的真實(shí)身份是HandlerMethod

//Exception ex就是接收到異常信息

@Override

public ModelAndView resolveException(HttpServletRequest request,

HttpServletResponse response, Object handler, Exception ex) {

//輸出異常

ex.printStackTrace();

//統(tǒng)一異常處理代碼

//針對(duì)系統(tǒng)自定義的CustomException異常膛薛,就可以直接從異常類中獲取異常信息,將異常處理在錯(cuò)誤頁(yè)面展示

//異常信息

String message = null;

CustomException customException = null;

//如果ex是系統(tǒng) 自定義的異常补鼻,直接取出異常信息

if(ex instanceof CustomException){

customException = (CustomException)ex;

}else{

//針對(duì)非CustomException異常哄啄,對(duì)這類重新構(gòu)造成一個(gè)CustomException,異常信息為“未知錯(cuò)誤”

customException = new CustomException("未知錯(cuò)誤");

}

//錯(cuò)誤 信息

message = customException.getMessage();

request.setAttribute("message", message);

try {

//轉(zhuǎn)向到錯(cuò)誤 頁(yè)面

request.getRequestDispatcher("/WEB-INF/jsp/error.jsp").forward(request, response);

} catch (ServletException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

return new ModelAndView();

}

}

2.2配置統(tǒng)一異常處理器

三风范、RESTful支持

我們?cè)趯W(xué)習(xí)webservice的時(shí)候可能就聽(tīng)過(guò)RESTful這么一個(gè)名詞咨跌,當(dāng)時(shí)候與SOAP進(jìn)行對(duì)比的…那么RESTful究竟是什么東東呢?硼婿?锌半?

RESTful(Representational State Transfer)軟件開(kāi)發(fā)理念,RESTful對(duì)http進(jìn)行非常好的詮釋寇漫。

如果一個(gè)架構(gòu)支持RESTful刊殉,那么就稱它為RESTful架構(gòu)…

以下的文章供我們了解:

http://www.ruanyifeng.com/blog/2011/09/restful

綜合上面的解釋,我們總結(jié)一下什么是RESTful架構(gòu):

(1)每一個(gè)URI代表一種資源州胳;

(2)客戶端和服務(wù)器之間冗澈,傳遞這種資源的某種表現(xiàn)層;

(3)客戶端通過(guò)四個(gè)HTTP動(dòng)詞陋葡,對(duì)服務(wù)器端資源進(jìn)行操作,實(shí)現(xiàn)"表現(xiàn)層狀態(tài)轉(zhuǎn)化"彻采。

關(guān)于RESTful冪等性的理解:http://www.oschina.net/translate/put-or-post

簡(jiǎn)單來(lái)說(shuō)腐缤,如果對(duì)象在請(qǐng)求的過(guò)程中會(huì)發(fā)生變化(以Java為例子,屬性被修改了)肛响,那么此是非冪等的岭粤。多次重復(fù)請(qǐng)求,結(jié)果還是不變的話特笋,那么就是冪等的剃浇。

PUT用于冪等請(qǐng)求,因此在更新的時(shí)候把所有的屬性都寫完整猎物,那么多次請(qǐng)求后虎囚,我們其他屬性是不會(huì)變的

在上邊的文章中,冪等被翻譯成“狀態(tài)統(tǒng)一性”蔫磨。這就更好地理解了淘讥。

其實(shí)一般的架構(gòu)并不能完全支持RESTful的,因此堤如,只要我們的系統(tǒng)支持RESTful的某些功能蒲列,我們一般就稱作為支持RESTful架構(gòu)…

3.1url的RESTful實(shí)現(xiàn)

非RESTful的http的url:http://localhost:8080/items/editItems.action?id=1&…

RESTful的url是簡(jiǎn)潔的:http:// localhost:8080/items/editItems/1

3.2更改DispatcherServlet的配置

從上面我們可以發(fā)現(xiàn)窒朋,url并沒(méi)有.action后綴的,因此我們要修改核心分配器的配置

<!-- restful的配置 -->

<servlet>

<servlet-name>springmvc_rest</servlet-name>

<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

<!-- 加載springmvc配置 -->

<init-param>

<param-name>contextConfigLocation</param-name>

<!-- 配置文件的地址 如果不配置contextConfigLocation蝗岖, 默認(rèn)查找的配置文件名稱classpath下的:servlet名稱+"-serlvet.xml"即:springmvc-serlvet.xml -->

<param-value>classpath:spring/springmvc.xml</param-value>

</init-param>

</servlet>

<servlet-mapping>

<servlet-name>springmvc_rest</servlet-name>

<!-- rest方式配置為/ -->

<url-pattern>/</url-pattern>

</servlet-mapping>

在Controller上使用PathVariable注解來(lái)綁定對(duì)應(yīng)的參數(shù)

//根據(jù)商品id查看商品信息rest接口

//@RequestMapping中指定restful方式的url中的參數(shù)侥猩,參數(shù)需要用{}包起來(lái)

//@PathVariable將url中的{}包起參數(shù)和形參進(jìn)行綁定

@RequestMapping("/viewItems/{id}")

public @ResponseBody ItemsCustom viewItems(@PathVariable("id") Integer id) throws Exception{

//調(diào)用 service查詢商品信息

ItemsCustom itemsCustom = itemsService.findItemsById(id);

return itemsCustom;

}

當(dāng)DispatcherServlet攔截/開(kāi)頭的所有請(qǐng)求,對(duì)靜態(tài)資源的訪問(wèn)就報(bào)錯(cuò):我們需要配置對(duì)靜態(tài)資源的解析

<!-- 靜態(tài)資源 解析 -->

<mvc:resources location="/js/" mapping="/js/**" />

<mvc:resources location="/img/" mapping="/img/**" />

/**就表示不管有多少層抵赢,都對(duì)其進(jìn)行解析欺劳,/*代表的是當(dāng)前層的所有資源…

四、SpringMVC攔截器

在Struts2中攔截器就是我們當(dāng)時(shí)的核心瓣俯,原來(lái)在SpringMVC中也是有攔截器的

用戶請(qǐng)求到DispatherServlet中杰标,DispatherServlet調(diào)用HandlerMapping查找Handler,HandlerMapping返回一個(gè)攔截的鏈兒(多個(gè)攔截)彩匕,springmvc中的攔截器是通過(guò)HandlerMapping發(fā)起的腔剂。

實(shí)現(xiàn)攔截器的接口:

public class HandlerInterceptor1 implements HandlerInterceptor {

//在執(zhí)行handler之前來(lái)執(zhí)行的

//用于用戶認(rèn)證校驗(yàn)、用戶權(quán)限校驗(yàn)

@Override

public boolean preHandle(HttpServletRequest request,

HttpServletResponse response, Object handler) throws Exception {

System.out.println("HandlerInterceptor1...preHandle");

//如果返回false表示攔截不繼續(xù)執(zhí)行handler驼仪,如果返回true表示放行

return false;

}

//在執(zhí)行handler返回modelAndView之前來(lái)執(zhí)行

//如果需要向頁(yè)面提供一些公用 的數(shù)據(jù)或配置一些視圖信息掸犬,使用此方法實(shí)現(xiàn) 從modelAndView入手

@Override

public void postHandle(HttpServletRequest request,

HttpServletResponse response, Object handler,

ModelAndView modelAndView) throws Exception {

System.out.println("HandlerInterceptor1...postHandle");

}

//執(zhí)行handler之后執(zhí)行此方法

//作系統(tǒng) 統(tǒng)一異常處理,進(jìn)行方法執(zhí)行性能監(jiān)控绪爸,在preHandle中設(shè)置一個(gè)時(shí)間點(diǎn)湾碎,在afterCompletion設(shè)置一個(gè)時(shí)間,兩個(gè)時(shí)間點(diǎn)的差就是執(zhí)行時(shí)長(zhǎng)

//實(shí)現(xiàn) 系統(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í)行 -->

<!-- <mvc:interceptor>

<mvc:mapping path="/**" />

<bean class="cn.itcast.ssm.controller.interceptor.HandlerInterceptor1"></bean>

</mvc:interceptor>

<mvc:interceptor>

<mvc:mapping path="/**" />

<bean class="cn.itcast.ssm.controller.interceptor.HandlerInterceptor2"></bean>

</mvc:interceptor> -->

<mvc:interceptor>

<!-- /**可以攔截路徑不管多少層 -->

<mvc:mapping path="/**" />

<bean class="cn.itcast.ssm.controller.interceptor.LoginInterceptor"></bean>

</mvc:interceptor>

</mvc:interceptors>

4.1測(cè)試執(zhí)行順序

如果兩個(gè)攔截器都放行

測(cè)試結(jié)果:

HandlerInterceptor1...preHandle

HandlerInterceptor2...preHandle

HandlerInterceptor2...postHandle

HandlerInterceptor1...postHandle

HandlerInterceptor2...afterCompletion

HandlerInterceptor1...afterCompletion

總結(jié):

執(zhí)行preHandle是順序執(zhí)行奠货。

執(zhí)行postHandle介褥、afterCompletion是倒序執(zhí)行

1 號(hào)放行和2號(hào)不放行

測(cè)試結(jié)果:

HandlerInterceptor1...preHandle

HandlerInterceptor2...preHandle

HandlerInterceptor1...afterCompletion

總結(jié):

如果preHandle不放行,postHandle递惋、afterCompletion都不執(zhí)行柔滔。

只要有一個(gè)攔截器不放行,controller不能執(zhí)行完成

1 號(hào)不放行和2號(hào)不放行

測(cè)試結(jié)果:

HandlerInterceptor1...preHandle

總結(jié):

只有前邊的攔截器preHandle方法放行萍虽,下邊的攔截器的preHandle才執(zhí)行睛廊。

日志攔截器或異常攔截器要求

將日志攔截器或異常攔截器放在攔截器鏈兒中第一個(gè)位置,且preHandle方法放行

4.2攔截器應(yīng)用-身份認(rèn)證

攔截器攔截

public class LoginInterceptor implements HandlerInterceptor {

//在執(zhí)行handler之前來(lái)執(zhí)行的

//用于用戶認(rèn)證校驗(yàn)杉编、用戶權(quán)限校驗(yàn)

@Override

public boolean preHandle(HttpServletRequest request,

HttpServletResponse response, Object handler) throws Exception {

//得到請(qǐng)求的url

String url = request.getRequestURI();

//判斷是否是公開(kāi) 地址

//實(shí)際開(kāi)發(fā)中需要公開(kāi) 地址配置在配置文件中

//...

if(url.indexOf("login.action")>=0){

//如果是公開(kāi) 地址則放行

return true;

}

//判斷用戶身份在session中是否存在

HttpSession session = request.getSession();

String usercode = (String) session.getAttribute("usercode");

//如果用戶身份在session中存在放行

if(usercode!=null){

return true;

}

//執(zhí)行到這里攔截超全,跳轉(zhuǎn)到登陸頁(yè)面,用戶進(jìn)行身份認(rèn)證

request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);

//如果返回false表示攔截不繼續(xù)執(zhí)行handler邓馒,如果返回true表示放行

return false;

}

//在執(zhí)行handler返回modelAndView之前來(lái)執(zhí)行

//如果需要向頁(yè)面提供一些公用 的數(shù)據(jù)或配置一些視圖信息嘶朱,使用此方法實(shí)現(xiàn) 從modelAndView入手

@Override

public void postHandle(HttpServletRequest request,

HttpServletResponse response, Object handler,

ModelAndView modelAndView) throws Exception {

System.out.println("HandlerInterceptor1...postHandle");

}

//執(zhí)行handler之后執(zhí)行此方法

//作系統(tǒng) 統(tǒng)一異常處理,進(jìn)行方法執(zhí)行性能監(jiān)控光酣,在preHandle中設(shè)置一個(gè)時(shí)間點(diǎn)见咒,在afterCompletion設(shè)置一個(gè)時(shí)間,兩個(gè)時(shí)間點(diǎn)的差就是執(zhí)行時(shí)長(zhǎng)

//實(shí)現(xiàn) 系統(tǒng) 統(tǒng)一日志記錄

@Override

public void afterCompletion(HttpServletRequest request,

HttpServletResponse response, Object handler, Exception ex)

throws Exception {

System.out.println("HandlerInterceptor1...afterCompletion");

}

}

Controller

@Controller

public class LoginController {

//用戶登陸提交方法

@RequestMapping("/login")

public String login(HttpSession session, String usercode,String password)throws Exception{

//調(diào)用service校驗(yàn)用戶賬號(hào)和密碼的正確性

//..

//如果service校驗(yàn)通過(guò)挂疆,將用戶身份記錄到session

session.setAttribute("usercode", usercode);

//重定向到商品查詢頁(yè)面

return "redirect:/items/queryItems.action";

}

//用戶退出

@RequestMapping("/logout")

public String logout(HttpSession session)throws Exception{

//session失效

session.invalidate();

//重定向到商品查詢頁(yè)面

return "redirect:/items/queryItems.action";

}

}

五改览、總結(jié)

使用Spring的校驗(yàn)方式就是將要校驗(yàn)的屬性前邊加上注解聲明下翎。

在Controller中的方法參數(shù)上加上@Validation注解。那么SpringMVC內(nèi)部就會(huì)幫我們對(duì)其進(jìn)行處理(創(chuàng)建對(duì)應(yīng)的bean宝当,加載配置文件)

BindingResult可以拿到我們校驗(yàn)錯(cuò)誤的提示

分組校驗(yàn)就是將讓我們的校驗(yàn)更加靈活:某方法需要校驗(yàn)這個(gè)屬性视事,而某方法不用校驗(yàn)該屬性。我們就可以使用分組校驗(yàn)了庆揩。

對(duì)于處理異常俐东,SpringMVC是用一個(gè)統(tǒng)一的異常處理器類的。實(shí)現(xiàn)了HandlerExceptionResolver接口订晌。

對(duì)模塊細(xì)分多個(gè)異常類虏辫,都交由我們的統(tǒng)一異常處理器類進(jìn)行處理。

對(duì)于RESTful規(guī)范锈拨,我們可以使用SpringMVC簡(jiǎn)單地支持的砌庄。將SpringMVC的攔截.action改成是任意的。同時(shí)奕枢,如果是靜態(tài)的資源文件瘪板,我們應(yīng)該設(shè)置不攔截隘庄。

對(duì)于url上的參數(shù)残吩,我們可以使用@PathVariable將url中的{}包起參數(shù)和形參進(jìn)行綁定

SpringMVC的攔截器和Struts2的攔截器差不多总放。不過(guò)SpringMVC的攔截器配置起來(lái)比Struts2的要簡(jiǎn)單。

至于他們的攔截器鏈的調(diào)用順序谷浅,和Filter的是沒(méi)有差別的扒俯。

至此,關(guān)于快速上手SpringMVC的知識(shí)點(diǎn)以及詳細(xì)介紹都在文章里面了一疯。文章中黑體字是重點(diǎn)陵珍,這樣做是為了讓各位小伙伴更好的閱讀!

如果覺(jué)得本文對(duì)你有益违施,請(qǐng)點(diǎn)贊關(guān)注碼農(nóng)石頭,持續(xù)更新干貨知識(shí)瑟幕。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末磕蒲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子只盹,更是在濱河造成了極大的恐慌辣往,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件殖卑,死亡現(xiàn)場(chǎng)離奇詭異站削,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)孵稽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門许起,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)十偶,“玉大人,你說(shuō)我怎么就攤上這事园细〉牖” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵猛频,是天一觀的道長(zhǎng)狮崩。 經(jīng)常有香客問(wèn)我,道長(zhǎng)鹿寻,這世上最難降的妖魔是什么睦柴? 我笑而不...
    開(kāi)封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮毡熏,結(jié)果婚禮上坦敌,老公的妹妹穿的比我還像新娘。我一直安慰自己招刹,他們只是感情好恬试,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著疯暑,像睡著了一般训柴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上妇拯,一...
    開(kāi)封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天幻馁,我揣著相機(jī)與錄音,去河邊找鬼越锈。 笑死仗嗦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的甘凭。 我是一名探鬼主播稀拐,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼丹弱!你這毒婦竟也來(lái)了德撬?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤躲胳,失蹤者是張志新(化名)和其女友劉穎蜓洪,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體坯苹,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡隆檀,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恐仑。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡泉坐,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出菊霜,到底是詐尸還是另有隱情坚冀,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布鉴逞,位于F島的核電站记某,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏构捡。R本人自食惡果不足惜液南,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望勾徽。 院中可真熱鬧滑凉,春花似錦、人聲如沸喘帚。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)吹由。三九已至若未,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間倾鲫,已是汗流浹背粗合。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留乌昔,地道東北人隙疚。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像磕道,于是被迫代替她去往敵國(guó)和親供屉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348