1 Spring MVC簡介javascript
l 官方的下載網址是:http://www.springsource.org/downloadhtml
l 咱們用Struts2時採用的傳統的配置文件的方式,並無使用傳說中的0配置Spring3 mvc能夠認爲已經100%零配置了前端
l Spring會比Struts快,在Struts中默認配置了不少缺省的攔截器,在給開發者提供便利的同時,失去了靈活性和效率.java
l Spring mvc是基於方法的設計, 而Sturts是基於類,每次發一次請求都會實例一個action,每一個action都會被注入屬性,而spring基於方法,粒度更細,可控制更強jquery
l 設計思想上:Struts更加符合oop的編程思想,Spring是在在Servlet上擴展,使用AOP實現。web
l Intercepter的實現機制:Struts有以本身的interceptor機制,Spring mvc用的是獨立的AOP方式. 須要的本身配置,比較麻煩當性能較優,靈活性高ajax
mvc/aop/core相關包。spring
新建spring-mvc.xml文件apache
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd "> </beans>
org.springframework.web.servlet.DispatcherServlet,繼承HttpServlet,須要在Web.xml文件中定義編程
<?xml version="1.0" encoding="UTF-8"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <display-name></display-name> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <servlet> <servlet-name>mvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mvc</servlet-name> <url-pattern>*.action</url-pattern> </servlet-mapping> </web-app>
建立控制器FirstAction.java,實現Controller接口
// action實現Controller接口,並實現handleRequest方法(相似service方法),與JSP內置對象偶合
public class FirstAction implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { // TODO Auto-generated method stub System.out.println("傳入的數據爲"); String userName=request.getParameter("userName"); String pwd=request.getParameter("pwd"); System.out.println("userName:"+userName); System.out.println("這裏能夠調用業務層處理業務。"); //封裝數據,能夠直接使用request對象,也能夠使用封裝等方式,真正使用時能夠選擇一種 request.setAttribute("rUserName", userName); Map<String, String > map=new HashMap<String, String>(); map.put("mUserName",userName); //返回視圖層,若是使用map封裝數據,須要做爲(第二個)參數傳遞,也是request做用域。 return new ModelAndView("/jsp/first.jsp",map); //返回視圖層,不傳遞map。 //return new ModelAndView("/jsp/first.jsp"); //也能夠使用以下方式傳遞,不使用Map,數據同樣是request做用域 //return new ModelAndView("/jsp/first.jsp","mUserName",userName); } }
修改spring-mvc.xm.文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd "> <!-- 1。配置action,實現controler接口 2。配置映射處理器,用來處理請求與action的映射,能夠不用寫id, 3。配置視圖解析器:完成ModelAndView的解析 缺點: 1。與JSP偶合 2。只支持屬性的注入,不支持封閉後對象注入 --> <!-- 聲明bean的name,由於使用了BeanNameUrlHandlerMapping,因此不是定義id,用戶調用的URL將經過bean的name匹配 --> <bean name="/first.action" class="cn.it.action.FirstAction" /> <!-- 聲明 BeanNameUrlHandlerMapping,使用名稱映射--> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> <!-- 支持servlet與jsp視圖解析,可進行進一步處理,此步可省略, --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 能夠加前綴或後綴 --> <!-- <property name="prefix" value="/jsp/"/> <property name="suffix" value=".jsp"/> --> </bean>
新建目錄jsp及目錄下新建first.jsp,用來展示訪問結果。
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <html> <head> <title>My JSP 'index.jsp' starting page</title> </head> <body> 這是/jsp/first.jsp頁面.<br/> <!-- 獲取並展示控制層傳遞過來的值 --> 直接經過request傳遞的值:${requestScope.rUserName}<br/>經過Map傳遞的值:${requestScope.mUserName} </body> </html>
編寫index.jsp用來訪問控制器
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <html> <head> <title>My JSP 'index.jsp' starting page</title> </head> <body> <a href="first.action?userName=zcf&pwd=admin">firstMVC</a> </body> </html>
BeanNameUrlHandlerMapping:它將收到的HTTP請求映射到bean的名稱(這些bean須要在web應用上下文中定義) <!-- 聲明bean的name,由於使用了BeanNameUrlHandlerMapping,因此不是定義id,用戶調用的URL將經過bean的name匹配 --> <bean name="/first.action" class="cn.it.action.FirstAction" /> <!-- 聲明 BeanNameUrlHandlerMapping,使用名稱映射 --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
SimpleUrlHandlerMapping:它將收到的HTTP請求映射到bean的ID(這些bean須要在web應用上下文中定義)
<!-- 配置URL與ACTION對象ID進行映射 ,<prop key="second.action">second</prop>,其中key匹配url信息,value爲action的ID --> <bean id="first" class="cn.it.action.FirstAction" /> <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="first.action">first</prop> </props> </property> </bean>
<!-- 支持servlet與jsp視圖解析1,可進行進一步處理,此步可省略, -->
<!-- viewClass不一樣的配置,能夠解析不一樣的資源-->
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <!-- <property name="prefix" value="/jsp/"/> <property name="suffix" value=".jsp"/> --> </bean>
做爲UrlBasedViewResolver的子類, 它支持頁面jstl處理.
<!-- 支持servlet與jsp視圖解析,可進行進一步處理,此步可省略, --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 能夠加前綴或後綴 --> <property name="prefix" value="/jsp/"/> <property name="suffix" value=".jsp"/> </bean>
forward使用轉發方式:
return new ModelAndView("forward:/jsp/first.jsp",map);
//控制器採用註解,方法在返回字符串時,能夠使用:
return "forward:/jsp/first.jsp";
redirect重定向方式
return new ModelAndView("redirect:/jsp/first.jsp",map);
//控制器採用註解,方法在返回字符串時,能夠使用
return "redirect:/jsp/first.jsp";
在spring mvc中控制對象要實現此接口,而且必須實現handRequest方法。此控制器在接收到DispatcherServlet分配置 的請求時,執行handRequest方法,並 返回ModelAndView實例。
public class FirstAction implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { ... }
能夠將請求參數值自動設置到command對象中,便於後繼的使用。
public class Student implements Serializable { @Override public String toString() { return "Student [stuId=" + stuId + ", stuName=" + stuName + ", stuPwd=" + stuPwd + ", stuAge=" + stuAge + "]"; } /** * */ private static final long serialVersionUID = 1785249781500211272L; private Integer stuId; private String stuName; private String stuPwd; private Integer stuAge; public Integer getStuId() { return stuId; } public void setStuId(Integer stuId) { this.stuId = stuId; } public String getStuName() { return stuName; } public void setStuName(String stuName) { this.stuName = stuName; } public String getStuPwd() { return stuPwd; } public void setStuPwd(String stuPwd) { this.stuPwd = stuPwd; } public Integer getStuAge() { return stuAge; } public void setStuAge(Integer stuAge) { this.stuAge = stuAge; } }
public class StudentAction extends AbstractCommandController { public StudentAction(){ //配置student對象能夠注入 setCommandClass(Student.class); } @Override protected ModelAndView handle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, BindException arg3) throws Exception { // TODO Auto-generated method stub System.out.println("---接收數據---"); //方式1接收數據,只能每一個屬性都分開接書 String stuName=arg0.getParameter("stuName"); String stuPwd=arg0.getParameter("stuPwd"); System.out.println("方式1接收的數據爲:"+stuName+","+stuPwd); //方式2接收數據,實現對象屬性注入 Student student = (Student)arg2; System.out.println("方式2接收的數據爲:"+student); System.out.println("---調用業務層,進行業務處理,略---"); //封裝視圖數據,有多種方式 ,這裏列表方式 一和方式 二,能夠任選一種: //方式一,直接採用request對象封裝 arg0.setAttribute("rStudent", student); //封裝視圖數據,方式二,直接採用Map封裝,默認做用域是request,須要在return的時候做爲參數傳遞。 Map<String ,Student > map=new HashMap<String, Student>(); map.put("mStudent", student); //默認爲forward方式 return new ModelAndView("/jsp/main.jsp",map); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd "> <bean id="student" class="cn.it.action.StudentAction"></bean> <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="student.action">student</prop> </props> </property> </bean> </beans>
/jsp/main.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <html> <head> <title>My JSP 'main.jsp' starting page</title> </head> <body> 這是/jsp/main.jsp頁面.<br/> <!-- 獲取並展示控制層傳遞過來的值 --> 直接經過request傳遞的值:${requestScope.rStudent}<br/>經過Map傳遞的值:${requestScope.mStudent} </body> </html>
添加登錄測試頁面
index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <html> <head> <title>My JSP 'index.jsp' starting page</title> </head> <body> <a href="student.action?stuName=zcf&stuPwd=admin">test student</a> </body> </html>
除action類之外,其它繼續使用上面的代碼
public class StudentMultiAction extends MultiActionController { //定義方法時,參數規則:(HttpServletRequest request, HttpServletResponse response, [,HttpSession session] [,MyObject]); public ModelAndView add(HttpServletRequest request,HttpServletResponse response,Student student){ System.out.println("add.student:"+student); student.setStuName("rename"); return new ModelAndView("jsp/main","student",student); } //定義方法時,參數規則:(HttpServletRequest request, HttpServletResponse response, [,HttpSession session] [,MyObject]); public ModelAndView update(HttpServletRequest request,HttpServletResponse response,Student student){ System.out.println("update.student:"+student); student.setStuName("rename"); return new ModelAndView("jsp/main","student",student); } //定義方法時,參數規則:(HttpServletRequest request, HttpServletResponse response, [,HttpSession session] [,MyObject]); public ModelAndView list(HttpServletRequest request,HttpServletResponse response,Student student){ System.out.println("list.student:"+student); student.setStuName("updateName"); return new ModelAndView("jsp/main"); } }
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd "> <!-- 配置控制器,並指定經過methodNameResolver方法名調用相關方法處理相關邏輯--> <bean id="studentMultiAction" class="cn.it.action.StudentMultiAction"> <property name="methodNameResolver" ref="parameterMethodNameResolver"></property> </bean> <!-- 定義經過方法名調用控制器相關方法的規則 --> <bean id="parameterMethodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver"> <!-- 在url中使用do=方法名方式識別相關方法,例如:studentMulti.action?do=add,將調用add方法;這裏的do不是固定的,能夠改成其它 --> <property name="paramName" value="do" /> <!-- 若是沒有指定方法名時,默認 調用控制器的list方法 --> <property name="defaultMethodName" value="list" /> </bean> <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/studentMulti.action">studentMultiAction</prop> </props> </property> </bean> <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property> <property name="prefix" value="/WEB-INF/" /> <property name="suffix" value=".jsp" /> </bean> </beans>
index.jsp關鍵代碼
<body> <form action="studentMulti.action?do=add" method="post"> <input type="text" name="stuName"><br> <input type="password" name="stuPwd"><br> <input type="submit" value="student_add"> </form> <a href="studentMulti.action?do=update&stuPwd=testpwd&stuName=testName">調用修改方法</a> <a href="studentMulti.action?&stuPwd=testpwd&stuName=testName">調用默認方法</a> </body>
/WEB-INF/jsp/main.jsp關鍵代碼
<body> this is WEB-INF/JSP main jsp<br> studentName:${requestScope.student.stuName}<br> </body>
繼續使用上面的代碼(注意新建項目記得從新配置web.xml文件)
添加DefaultAnnotationHandlerMapping,AnnotationMethodHandlerAdapter等相關信息。其中
DefaultAnnotationHandlerMapping:支持經過url找到相關的action
AnnotationMethodHandlerAdapter:支持經過url匹配action定義方法
base-package:定 義掃描的範圍,spring能夠自動去掃描base-pack下面或者子包下面的java文件,若是掃描到有@Component @Controller@Service等這些註解的類,則把這些類註冊爲bean
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd "> <!-- DefaultAnnotationHandlerMapping:支持經過url找到相關的action AnnotationMethodHandlerAdapter:支持經過url匹配action定義方法 base-package:定 義掃描的範圍,spring能夠自動去掃描base-pack下面或者子包下面的java文件,若是掃描到有@Component @Controller@Service等這些註解的類,則把這些類註冊爲bean --> <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"></bean> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"></bean> <context:component-scan base-package="*"></context:component-scan> </beans>
加入@Controller,@RequestMapping註解信息
@Controller //用來聲明控制器
@RequestMapping("/student") public class StudentAction { public StudentAction(){ System.out.println("---StudentAction構造方法被調用---"); }
//訪問可用student/save.action,save後邊的action是根據web.xml配置來的
//若是要添加其它的數據到最後跳轉過去的頁面,能夠在方法中添加ModelMap的參數,例如 : public String save(Student student,ModelMap map){
//...,經過map再存放其它的數據
@RequestMapping(value="/save") public ModelAndView save(Student student){ System.out.println("save方法注入的student對象:"+student); System.out.println("---調用業務邏輯進行業務處理---"); //修改學生名字,跳轉到下一頁面時看可否顯示修改後的名字 student.setStuName("rename"); //直接使用字符串,返回視圖,進行結果展示等 return new ModelAndView("forward:/jsp/main.jsp"); } //同一個action中能夠定義多個方法,方法的返回類型也能夠用String @RequestMapping(value="/update") public String update(Student student,ModelMap paramMap){ System.out.println("update方法已注入student對象:"+student); System.out.println("---調用業務邏輯進行業務處理---"); paramMap.put("other","testOtherValue"); //直接使用字符串,返回視圖,進行結果展示等 return "forward:/jsp/main.jsp"; } }
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <html> <head> <title>My JSP 'main.jsp' starting page</title> </head> <body> 這是/jsp/main.jsp頁面.<br/> <!-- 獲取並展示控制層傳遞過來的值 --> 默認經過request傳遞的值:${requestScope.student}<br/> </body> </html>
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <html> <head> <title>My JSP 'index.jsp' starting page</title> </head> <body> <a href="student/save.action?stuName=zcf&stuPwd=admin">調用save方法</a> <a href="student/update.action?stuName=zcf&stuPwd=admin">調用update方法</a> </body> </html>
基於上面的示例,在spring3中能夠進一步簡化配置,取代上面的註解方式.
步驟以下
1.使用上面的action類,仍然給類及方法添加@Controller(類)、@RequestMapping(類及方法)註解
2.本文件頂部添加spring mvc 命名空間的信息(能夠參考org.springframework.web.servlet.config包)
3.添加下面註解驅動<mvc:annotation-driven>,取代了上面的DefaultAnnotationHandlerMapping,AnnotationMethodHandlerAdapter,並啓動了json的註解
-->
修改內容以下:
修改spring-mvc.xml文件, 紅色部分:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd "> <!-- <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"></bean> <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"></bean> <context:component-scan base-package="*"></context:component-scan> --> <!-- mvc:annotation-driven,取代了上面的DefaultAnnotationHandlerMapping,AnnotationMethodHandlerAdapter 兩個Bean的配置 --> <mvc:annotation-driven></mvc:annotation-driven> <context:component-scan base-package="*"/> </beans>
Spring 2.0 定義了一個 org.springframework.ui.ModelMap 類,它做爲通用的模型數據承載對象,傳遞數據供視圖所用。咱們能夠在請求處理方法中聲明一個 ModelMap 類型的入參,Spring 會將本次請求模型對象引用經過該入參傳遞進來,這樣就能夠在請求處理方法內部訪問模型對象了在默認狀況下,ModelMap 中的屬性做用域是 request 級別是,也就是說,當本次請求結束後,ModelMap 中的屬性將銷燬,但實際上有時候須要把ModelMap值存放於session中或有時候也能夠從Session中獲取對象的值注入到ModelMap中。
繼續使用上面的代碼
若是但願在多個請求中共享 ModelMap 中的屬性,必須將其屬性轉存到 session 中,這樣 ModelMap 的屬性才能夠被跨請求訪問;
能夠在定義 類時使用@SessionAttributes("屬性名")或@SessionAttributes({「attr1」,」attr2」})等方式將嘗試從modelMap中尋找相同屬性名相應的value.
@Controller @RequestMapping("/student") //下邊若有多個屬性能夠用 @SessionAttributes({「attr1」,」attr2」})。 @SessionAttributes("user") public class StudentAction { public StudentAction(){ System.out.println("---StudentAction構造方法被調用---"); } @RequestMapping(value="/save") public String save(Student student,ModelMap map){ System.out.println("---調用業務邏輯進行業務處理---"); Student s2=new Student(); s2.setStuAge(11); s2.setStuId(11111); map.addAttribute("user", s2);//屬性名必須與session一致 //map.addAttribute("stu", student); //直接使用字符串,返回視圖,進行結果展示等 return "forward:/jsp/main.jsp"; } //同一個action中能夠定義多個方法 @RequestMapping(value="/update") public String update(Student student){ System.out.println("update方法已注入student對象:"+student); System.out.println("---調用業務邏輯進行業務處理---"); paramMap.put("student",student); //直接使用字符串,返回視圖,進行結果展示等 return "forward:/jsp/main.jsp"; } }
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <html> <head> <title>My JSP 'main.jsp' starting page</title> </head> <body> 這是/jsp/main.jsp頁面.<br/> <!-- 獲取並展示控制層傳遞過來的值 --> 默認直接經過request傳遞的值:${requestScope.student}<br/> <!-- 默認直接經過session傳遞的值stu:${sessionScope.stu}<br/> --> 默認直接經過session傳遞user值:${sessionScope.user}<br/> <!--下邊的代碼給下一示例使用:調用update方法測試把session的值注入到map中,此時session已經有user相關信息--> <a href="../student/update.action">session的值注入到map中</a> </body> </html>
在參數中使用@ModelAttribute("user"),能夠獲取@SessionAttributes("user")值
繼續使用上面代碼
定義類時繼續使用@SessionAttributes("user"),並修改update方法,在參數中添加@ModelAttribute("user"):參數中的student的對象將由session中獲取。
@Controller @RequestMapping("/student") //下邊若有多個屬性能夠用 @SessionAttributes({「attr1」,」attr2」})。 @SessionAttributes("user") public class StudentAction { public StudentAction(){ System.out.println("---StudentAction構造方法被調用---"); } @RequestMapping(value="/save") public String save(Student student,ModelMap map){ System.out.println("---調用業務邏輯進行業務處理---"); Student s2=new Student(); s2.setStuAge(11); s2.setStuId(11111); s2.setStuName("testname"); map.addAttribute("user", s2); //map.addAttribute("stu", student); //直接使用字符串,返回視圖,進行結果展示等 return "forward:/jsp/main.jsp"; } //同一個action中能夠定義多個方法 @RequestMapping(value="/update") public String update(@ModelAttribute("user")Student student){ System.out.println("update方法已注入student對象:"+student); System.out.println("---調用業務邏輯進行業務處理---"); //直接使用字符串,返回視圖,進行結果展示等 return "forward:/jsp/main.jsp"; } }
在綜合示例1上繼續。
LoginInterceptor.java,須要實現HandlerInterceptor接口
public class LoginInterceptor implements HandlerInterceptor { @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { // TODO Auto-generated method stub System.out.println("---訪問請求資源後無論理有沒有異常都必定執行此方法---"); } @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { // TODO Auto-generated method stub System.out.println("---訪問請求資源後,若是沒有異常,將執行此方法---"); } @Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { // TODO Auto-generated method stub System.out.println("---訪問請求資源前執行,若是此方法返回false,將不能訪問請求資源---"); return true; } }
<!-- 配置spring mvc攔截器 --> <mvc:interceptors> <!-- 默認攔截DispatcherServlet指定的後綴(這裏是.action) --> <bean class="cn.it.interceptor.LoginInterceptor"/> </mvc:interceptors>
添加攔截器類及攔截器配置信息,如上面。
@Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { // TODO Auto-generated method stub System.out.println("---訪問請求資源前執行,若是此方法返回false,將不能訪問請求資源---"); if(arg0.getSession().getAttribute("user")==null){ arg1.sendRedirect(arg0.getContextPath()+"/login.jsp"); return false; } return true; }
login.jsp,本頁面已模仿了登錄
<%@page import="cn.it.entity.Student"%> <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <html> <head> <title>My JSP 'index.jsp' starting page</title> </head> <body> <% session.setAttribute("user", new Student(1001,"zcf","admin",20)); %> <!-- 這裏正常應該跳到action再到頁面 ,爲了演示,這裏簡略--> <a href="index.jsp">已登錄,返回首頁</a> </body> </html>
7.4多個攔截器使用
HandlerInterceptor1代碼以下,HandlerInterceptor2代碼略
public class HandlerInterceptor1 implements HandlerInterceptor { @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { System.out.println("HandlerInterceptor1.afterCompletion"); } @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { System.out.println("HandlerInterceptor1.postHandle"); } @Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { System.out.println("HandlerInterceptor1.preHandle"); return false; } }
<mvc:interceptors> <!-- 默認攔截DispatcherServlet指定的後綴(這裏是.action) --> <!-- 配置多個攔截器,將按配置順序執行 --> <mvc:interceptor> <!-- 若是須要攔截全部,能夠發下配置「/**」表示攔截全部url --> <mvc:mapping path="/**"/> <bean class="cn.it.interceptors.HandlerInterceptor1"></bean> </mvc:interceptor> <mvc:interceptor> <!-- 若是須要攔截全部,能夠發下配置「/**」表示攔截全部url --> <mvc:mapping path="/**"/> <bean class="cn.it.interceptors.HandlerInterceptor2"></bean> </mvc:interceptor> </mvc:interceptors>
只輸出:
Interceptor1.preHandle
輸出
Interceptor1.preHandle
Interceptor2.preHandle
Interceptor1.afterCompletion
輸出
Interceptor1.preHandle
輸出:
Interceptor1.preHandle
Interceptor2.preHandle
save方法注入的student對象:Student [stuId=null, stuName=zcf, stuPwd=admin, stuAge=null]
Interceptor2.postHandle
Interceptor1.postHandle
Interceptor2.afterCompletion
Interceptor1.afterCompletion
spring-mvc.xml文件添加以下內容:
<!--文件上傳使用, 配置multipartResolver,id名爲約定好的 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 配置文件(每次上傳的全部文件總大小)大小,單位爲b, 1024000表示1000kb --> <property name="maxUploadSize" value="1024000" /> </bean>
web.xml文件添加以下內容:
<filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
若是上邊的方式設置後,仍然有亂碼,請嘗試修改tomcat安裝目錄下的
apache-tomcat安裝目錄\conf\server.xml文件,修改Connector元素內容,添加URIEncoding="UTF-8" ,修改後內容 以下:
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8"/>
PropertiesFactoryBean:用來注入properties類型的配置文件信息
<!--PropertiesFactoryBean對properties文件可用 ,能夠用來注入properties配置文件的信息 --> <bean id="uploadProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="location" value="classpath:xxxxx.properties"></property> </bean>
繼續使用上一章節代碼,並導入文件上傳須要的jar包:commons-fileupload-1.2.2.jar, commons-io-2.0.1.jar
public class Student implements Serializable { private static final long serialVersionUID = -5304386891883937131L; private Integer stuId; private String stuName; private String stuPwd; private Integer stuAge; private MultipartFile[] files; public MultipartFile[] getFiles() { return files; } public void setFiles(MultipartFile[] files) { this.files = files; } public Integer getStuId() { return stuId; } public void setStuId(Integer stuId) { this.stuId = stuId; } public String getStuName() { return stuName; } public void setStuName(String stuName) { this.stuName = stuName; } public String getStuPwd() { return stuPwd; } public void setStuPwd(String stuPwd) { this.stuPwd = stuPwd; } public Integer getStuAge() { return stuAge; } public void setStuAge(Integer stuAge) { this.stuAge = stuAge; } @Override public String toString() { return "Student [stuId=" + stuId + ", stuName=" + stuName + ", stuPwd=" + stuPwd + ", stuAge=" + stuAge + "]"; } }
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <html> <head> <title>My JSP 'index.jsp' starting page</title> </head> <body> <form action="student/save.action" method="post" enctype="multipart/form-data"> 姓名:<input type="text" name="stuName"><br/> 密碼<input type="password" name="stuPwd"><br> 請選擇文件:<br/><input type="file" name="files"><br/> <input type="file" name="files"><br/> <input type="submit" value="文件上傳測試"> </form> </body> </html>
StudentAction.java @Controller @RequestMapping("/student") public class StudentAction { public StudentAction(){ System.out.println("---StudentAction構造方法被調用---"); } @RequestMapping("/save") public String save(Student student) { System.out.println("save方法已注入student對象:"+student); MultipartFile[] files=student.getFiles(); for(MultipartFile file:files){ if(file.isEmpty()){ System.out.println("文件爲空"); }else{ System.out.println("文件不爲空!"); System.out.println("格式:" + file.getContentType()); System.out.println("原名:" + file.getOriginalFilename()); System.out.println("大小:" + file.getSize()); System.out.println("表單控件的名稱" + file.getName()); try { FileUtils.copyInputStreamToFile(file.getInputStream(), new File("e:/testupload/"+file.getOriginalFilename())); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } System.out.println("---調用業務邏輯進行業務處理---"); //直接使用字符串,返回視圖,進行結果展示等 return "forward:/jsp/main.jsp"; } }
添加文件處理器CommonsMultipartResolver配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd "> <mvc:annotation-driven></mvc:annotation-driven> <context:component-scan base-package="*"/> <!--文件上傳使用, 配置multipartResolver,id名稱爲約定好的 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 配置文件(每次上傳的全部文件總大小)大小,單位爲b, 1024000表示1000kb --> <property name="maxUploadSize" value="1024000" /> </bean> </beans>
main.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <html> <head> <title>main.jsp</title> </head> <body> /jsp/main.jsp頁面 student: ${requestScope.student} </body> </html>
l 在項目目錄下新建upload文件夾
l 修改StudentAction.java。
@Controller @RequestMapping("/student") public class StudentAction { public StudentAction(){ System.out.println("---StudentAction構造方法被調用---"); } @Resource ServletContext application; @RequestMapping("/save") public String save(Student student) { System.out.println("save方法已注入student對象:"+student); MultipartFile[] files=student.getFiles(); System.out.println("真實路徑:"+application.getRealPath("/")); for(MultipartFile file:files){ if(file.isEmpty()){ System.out.println("文件爲空"); }else{ System.out.println("文件不爲空!"); System.out.println("格式:" + file.getContentType()); System.out.println("原名:" + file.getOriginalFilename()); System.out.println("大小:" + file.getSize()); System.out.println("表單控件的名稱" + file.getName()); try { FileUtils.copyInputStreamToFile(file.getInputStream(), new File(application.getRealPath("/")+"upload/"+file.getOriginalFilename())); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } System.out.println("---調用業務邏輯進行業務處理---"); //直接使用字符串,返回視圖,進行結果展示等 return "forward:/jsp/main.jsp"; } }
其它代碼同上一章節,能夠在application.getRealPath("/")+"upload/"目錄下查看到文件,例如 :
E:\Users\chufeng\Workspaces\MyEclipse10\it\.metadata\.me_tcat\webapps\fileuploadspring\upload查看到上傳的文件。
FileUploadUtil.java
@Component(value="fileUploadUtils") //普通的bean注入 public class FileUploadUtils { /* * 注入字符串,#{}爲spel語言,其中uploadProperties,是xml配置文件中注入properties文件的bean id, * path爲properties文件的其中一個key ,也能夠經過下邊的set方法注入 */ @Value("#{uploadProperties.path}") private String path; //private String path="e:/testupload"; //path也能夠經過set方法注入 // @Value("#{uploadProperties.path}") // public void setPath(String path) { // this.path = path; // } private String getExtName(MultipartFile file){ return FilenameUtils.getExtension(file.getOriginalFilename()); } private String createNewName(MultipartFile file){ return UUID.randomUUID().toString()+"."+getExtName(file); } public String uploadFile(MultipartFile file){ try { String newName=createNewName(file); FileUtils.copyInputStreamToFile(file.getInputStream(), new File(path,newName )); return newName; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); throw new RuntimeException(e); } } }
主要修改save方法,使用自已的文件上傳工具類進行文件上傳。
@Controller @RequestMapping(value="/student") public class StudentAction { @Resource private ServletContext application; @Resource private FileUploadUtils fileUploadUtils; public StudentAction(){ System.out.println("---StudentAction構造方法被調用---"); } @RequestMapping(value="/save") public String save(Student student,Map<String, Student> paramMap) { System.out.println("save方法已注入student對象:"+student); MultipartFile[] files=student.getFiles(); for(MultipartFile file:files){ if(file.isEmpty()){ System.out.println("文件爲空"); }else{ System.out.println("文件不爲空!"); fileUploadUtils.uploadFile(file); } } System.out.println("---調用業務邏輯進行業務處理---"); paramMap.put("student",student); //直接使用字符串,返回視圖,進行結果展示等 return "forward:/jsp/main.jsp"; } }
配置文件上傳後的存放目錄
path=e\:\\testdir\\upload\\
注入配置文件的信息
<!--PropertiesFactoryBean對properties文件可用 ,能夠用來注入properties配置文件的信息 --> <bean id="uploadProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="location" value="classpath:upload.properties"></property> </bean>
系統異常處理:通常系統各層能夠向上拋出異常,最後再作統一的異常處理
dao-->service-->controler-->統一異常處理
spring mvc提供全局異常處理器進行統一異常處理
自定義異常,對預期的異常進行處理
public class CustomException extends Exception { public CustomException() {} public CustomException(String message) { super(message); } }
須要實現spring mvc 提供的HandlerExceptionResolver接口
public class CustomExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) { CustomException customException = null; if(arg3 instanceof CustomException){ customException = (CustomException)arg3; }else{ customException = new CustomException("末知錯誤,請聯繫管理員!");//能夠配置 } return new ModelAndView("forward:/error.jsp","errMsg",customException.getMessage()); } }
error.jsp
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>錯誤頁面</title> </head> <body> ${requestScope.errMsg} </body> </html>
<!-- 只要實現了HandlerExceptionResolver接口就是全局異常處理器 -->
<bean class="cn.it.resolver.CustomExceptionResolver"></bean>
<form action="student/add.action" method="post"> 姓名:<input type="text" name="stuName"><br> 密碼:<input type="text" name="stuPass"><br> <input type="submit" value="add"> </form>
@RequestMapping("/add") public String add(Student student,ModelMap map) throws Exception{ throw new CustomException("ddddd"); /*Integer.parseInt("dd"); System.out.println("add:"+student); map.addAttribute("user",student); return "forward:/jsp/main.jsp";*/ }
使用上面的源碼,暫時去掉攔截器的登錄權限處理
@Controller @RequestMapping(value="/student") public class StudentAction { public StudentAction(){ System.out.println("---StudentAction構造方法被調用---"); } @RequestMapping("/doAjax") @ResponseBody //若是返回json格式,須要這個註解 public Object doAjax(Student student){ System.out.println("---doAjax.student:"+student); student.setStuName("1001name"); return student; } }
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <html> <head> <title>My JSP 'index.jsp' starting page</title> <script type="text/javascript" src="${pageContext.request.contextPath}/jquery-1.3.js"></script> <script type="text/javascript"> $( function(){ $("#bt1").click( function(){ $.post( "student/doAjax.action", {stuId:1001,stuName:"name1001",stuPwd:"pwd1001",stuAge:20}, function(json){alert(json.stuName+"||"+json.stuPwd);}, "json" ); } ); } ); </script> </head> <body> <button id="bt1" >testajax</button> </body> </html