一涡戳、什么是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í)瑟幕。