一、Spring簡介 Spring MVC是當前最優秀的 MVC 框架,自從Spring 2.5 版本發佈後,由於支持註解配置,易用性有了大幅度的提高。Spring 3.0 更加完善,實現了對 Struts 2 的超越。現在越來越多的開發團隊選擇了Spring MVC。 1)Spring3 MVC使 ...
一、Spring簡介
Spring MVC是當前最優秀的 MVC 框架,自從Spring 2.5 版本發佈後,由於支持註解配置,易用性有了大幅度的提高。Spring 3.0 更加完善,實現了對 Struts 2 的超越。現在越來越多的開發團隊選擇了Spring MVC。
1)Spring3 MVC使用簡單,學習成本低。學習難度小於Struts2,Struts2用不上的多餘功能太多
2)Spring3 MVC很容易就可以寫出性能優秀的程式,Struts2要處處小心才可以寫出性能優秀的程式(指MVC部分)
3)靈活
√讓我們能非常簡單的設計出乾凈的Web層和薄薄的Web層;
√進行更簡潔的Web層的開發;
√天生與Spring框架集成(如IoC容器、AOP等);
√提供強大的約定大於配置的契約式編程支持;
√能簡單的進行Web層的單元測試;
√支持靈活的URL到頁面控制器的映射;
√非常容易與其他視圖技術集成,如Velocity、FreeMarker等等,因為模型數據不放在特定的API里,而是放在一個Model里(Map數據結構實現,因此很容易被其他框架使用);
√非常靈活的數據驗證、格式化和數據綁定機制,能使用任何對象進行數據綁定,不必實現特定框架的API;
√提供一套強大的JSP標簽庫,簡化JSP開發;
√支持靈活的本地化、主題等解析;
√更加簡單的異常處理;
√對靜態資源的支持;
√支持Restful風格
前端控制器是DispatcherServlet;
應用控制器其實拆為處理器映射器(Handler Mapping)進行處理器管理和視圖解析器(View Resolver)進行視圖管理;
頁面控制器/動作/處理器為Controller介面(僅包含ModelAndView handleRequest(request, response) 方法)的實現(也可以是任何的POJO類);
支持本地化(Locale)解析、主題(Theme)解析及文件上傳等;提供了非常靈活的數據驗證、格式化和數據綁定機制;
提供了強大的約定大於配置(慣例優先原則)的契約式編程支持。
二、配置核心控制器
1) 導包,配置環境
aopalliance-1.0.jar
bean-validator.jar
commons-fileupload-1.2.2.jar
commons-io-2.1.jar
commons-logging-1.2.jar
javax.servlet.jsp.jstl-1.2.1.jar
jsp-api-2.1.jar
jstl-1.2.jar
jstl-api-1.2.jar
mysql-connector-java-5.1.7-bin.jar
servlet-api-2.5.jar
spring-aop-4.1.4.RELEASE.jar
spring-beans-4.1.4.RELEASE.jar
spring-context-4.1.4.RELEASE.jar
spring-core-4.1.4.RELEASE.jar
spring-expression-4.1.4.RELEASE.jar
spring-web-4.1.4.RELEASE.jar
spring-webmvc-4.1.4.RELEASE.jar
standard-1.1.2.jar
2)
配置核心控制器
配置處理器映射器 handler Mapping
配置處理器適配器 handler Adapter
配置視圖解析器
2.1 配置核心控制器
在 web.xml 中
<servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 在 spring-webmvc-4.1.4.RELEASE.jar 下 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc-servlet.xml</param-value> //手動指定配置文件的路徑 </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> // 可以寫成*.do,*.action,但不能寫成杠* </servlet-mapping>
說明:
1 預設情況下,載入配置文件是 WEB-INF/servlet名稱-servlet.xml //springMVC-servlet.xml
2 如果想指定配置文件的路徑,可以加入參數進行指寫
三、配置
配置處理器映射器, 配置處理器適配器, 配置視圖解析器 (即配置主文件)
<!-- 配置處理器映射器 handler Mapping --> <bean name="/search_all" class="cat.controller.UserAction" /> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> <!-- 配置處理器適配器 handler Adapter --> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" /> <!-- 配置視圖解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" />
//Action 中的方法 public class UserAction implements Controller { //要實現 Controller public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { UserDao dao=new UserDao(); List<UserInfo> userList=dao.getAllUser(); ModelAndView mv=new ModelAndView(); mv.addObject("userList", userList); //相當於request.setAttribute(); mv.setViewName("user_manage.jsp"); return mv; } }
訪問的時候 http://localhost:8080/springmvc/search_all
附: user_manage.jsp
<body>
<c:forEach var="u" items="${userList }">
${u.id } | ${u.userName } | ${u.password } <br />
</c:forEach>
</body>
# Default implementation classes for DispatcherServlet s strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping= //處理器映射器
org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping //這個是3.1之前的
//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping 應該用這個才對
org.springframework.web.servlet.HandlerAdapter= //處理器適配器
org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter //這個是3.1之前的
//org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter 應該用這個才對
org.springframework.web.servlet.HandlerExceptionResolver=
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
使用註解的方式配置處理器映射器和處理器適配器
1) 配置文件 springmvc-servlet.xml
//開啟掃描 <context:component-scan base-package="cat.controller" /> //開啟註解配置 <mvc:annotation-driven /> /* 有了上面的配置,下麵的就可以不寫了 <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" /> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" /> */ <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" > //<property name="prefix" value="/WEB-INF/jsp/" /> <property name="prefix" value="/" /> <property name="suffix" value=".jsp" /> </bean>
2)
@Controller //這裡只能用 @Controller ,不能用 Service public class UserAction { @RequestMapping("/search_all") //請求的名稱,最好和方法名相同 public ModelAndView getAllUser(){ UserDao dao=new UserDao(); List<UserInfo> userList=dao.getAllUser(); ModelAndView mv=new ModelAndView(); mv.addObject("userList", userList); //相當於request.setAttribute(); mv.setViewName("user_manage.jsp"); return mv; } }
五、@RequestMapping 註解, 和 Action中方法的返回值
在上例中添加用主修改的功能
1) @RequestMappingr 的說明
@RequestMapping 用來將url 和方法名進行 映射 ,一個方法,對應一個url , 比如 @RequestMapping("/search_all") 後面可以加.action
可以用類,或方法上,用在類上,表示所有方法的根路徑
比如
@RequestMapping("/user") //寫在類體上 public class UserAction { ... }
RequestMappingr 註解有6個屬性 value,method,consumes,produces,params,headers
--value 指定請求的實際地址 -> @RequestMapping(value="/search_all")=@RequestMapping("/search_all")
--method 指定請求的method類型 (GET,POST,PUT,DELETE等)
例如
@RequestMapping(value="/updateUser" ,method=RequestMethod.POST)
@RequestMapping(value="/updateUser" ,method={RequestMethod.POST,RequestMethod.GET})
說明 如果請求類型不對則出現類似異常 Request method 'GET' not supported
-- consumes: 指定處理請求的提交內容類型(Content-Type),例如application/json, text/html;
-- produces: 指定返回的內容類型,僅當request請求頭中的(Accept)類型中包含該指定類型才返回
-- params: 指定request中必須包含某些參數值時,才讓該方法處理。 //實測發現如果指定了,不傳將出錯
-- headers:指定request中必須包含某些指定的header值,才能讓該方法處理請求。
2) Action中方法的返回值的說明
-- ModelAndView
-- String //如果返回的是String 類型,則代表返回的邏輯視圖名稱 (相當於struts2中的邏輯視圖 )
//例一 @RequestMapping(value="/updateUser" ,method=RequestMethod.GET) public String updateUser(Model model){ //用model 進行傳參 UserInfo user=new UserDao().getAdminById(4); model.addAttribute("user", user); return "user_edit"; }
//例二 關於請求的轉發和重定向 @RequestMapping(value="/updateUser" ,method=RequestMethod.POST) //只有請求是get請求的時候才有效 public String updateUserSubmit(){ System.out.println("-----"); //return "redirce:search_all" ; //重定向 search_all是一個請求的名稱 return "forward:search_all" ; }
-- void
//例子 @RequestMapping(value="/udpateUserSubmit") public void udpateUserSubmit(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException{ /* response.sendRedirect("search_all"); //重定向到某個url response.sendRedirect("success"); //404 request.getRequestDispatcher("/success.jsp").forward(request, response);*/ response.getWriter().print("<h1>哈哈哈,這樣也可以</h1>"); response.getWriter().print( "\"userName\":\"張三\",\"password\":\"123\"" ); //返回json數據 }
六、參數綁定與值的傳遞
頁面請求發起的時候,如何把值傳給Controller (//Action ),以及如何把模型數據進行傳遞
1) 在 Controller 的形參上,可以直接定使用以下對象
HttpServletRequest
HttpServletResponse
HttpSession
Model //public abstract interface org.springframework.ui.Model
MdelMap // org.springframework.ui.ModelMap
Map<String ,Object> //普通的map也可以,往這裡放的值,最終就放在了作用域中,在頁面就可以取出 ${key} ;
2) 可以使用簡單類型
//例一 @RequestMapping("/testParam") public void testParam(String userName,String password,String note){ System.out.println(userName+":"+password+":"+note); } //本例的前提 參數名和請求傳上來的參數名要一致
//例二 @RequestParam 註解的作用 @RequestMapping("/testParam2") public String testParam2( String userName, ModelMap mode, @RequestParam("password") String pwd, @RequestParam(value="age",required=true) int age, //標明是必須的,如果不傳將出錯 @RequestParam(value="school",defaultValue="農業工程學院") String school) { System.out.println("userName:"+userName); System.out.println("age:"+age); System.out.println("school:"+school); return "success"; }
3) 關於pojo類型(就是bean)
只要表單元素的名字和方法的參數中的屬性值相同卻可。
@RequestMapping(value="/updateUser",method=RequestMethod.POST) public String udpateUserSubmit(UserInfo user) { System.out.println(user); //這裡接收的參數是pojo類型 new UserDao().updateUser(user); return "success"; }
//user_edit.jsp <form action="${pageContext.request.contextPath }/updateUser" method="post"> //註意,提交方式是post id: <input type="text" name="id" value="${user.id }" /> 賬號: <input type="text" name="userName" value="${user.userName }" /> 密碼: <input type="text" name="password" value="${user.password }" /> 備註: <input type="text" name="note" value="${user.note }" /> <input type=submit value="提交" /> </form>
附:
處理亂碼spring的過濾器
<filter> <filter-name>CharacterEncodingFilter</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>CharacterEncodingFilter</filter-name> <url-pattern>杠*</url-pattern> </filter-mapping>
如果是get請求的亂碼怎麼處理?
public String test(HttpServletRequest request){ String userName=request.getParameter("userName"); userName=new String(userName.getBytes("iso8859-1"),"utf-8"); }
//上例或 在tomcat 的配置文件中(server.xml中加入 useBodyEncodingForURI=ture ) <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="utf-8" useBodyEncodingForURI=ture />
4) 關於日期類型
例: 在實體類中添加一個日期類型的欄位
private Date birthday; //生成get set
//在user_edit.jsp 頁面上 加上欄位
<input type="text" name="birthday" value="${user.birthday }" /> 可以發現,在提交的時候出
解決日期類型的問題有以下幾個方式
方式一:在實體類中加格式化註解
@DateTimeFormat(pattern="yyyy-MM-dd") //有效,簡單 private Date birthday;
方式二:在控制器中加入一段數據綁定代碼
@InitBinder public void initBinder(WebDataBinder binder) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); dateFormat.setLenient(false); binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true)); //true:允許輸入空值,false:不能為空值 } //此方式:對於某個Oontroller可以獨立控制
方式三:要向處理器適配器中註入自定義參數綁定組件
5) 包裝類型的pojo
public class UserInfoCustom { private UserInfo user; //包裝一個pojo類型 private String schoolName; //get set 方法.. }
user_add.jsp //用戶添加頁面
<form action="${pageContext.request.contextPath }/addUser" method="post"> 賬號: <input type="text" name="user.userName" /> 密碼: <input type="text" name="user.password" /> 備註: <input type="text" name="user.note" /> 學校: <input type="text" name="schoolName" /> //註意 <input type=submit value="提交" /> </form> //添加會員,用包裝類型的pojo傳值 @RequestMapping(value="/addUser",method=RequestMethod.POST) public String addUser(UserInfoCustom info){ System.out.println(info); //new UserDao().addUser(info) return "success"; }
6) 數組類型的綁定
user_manage.jsp
<form action="${pageContext.request.contextPath }/deleUser" method="post"> <c:forEach var="u" items="${userList }"> <input type="checkbox" name="ids" value="${u.id } "> ${u.id } | ${u.userName } | ${u.password } <br /> </c:forEach> <input type="submit" value="刪除所選" > </form>
控制層中業務方法
@RequestMapping("/deleUser") public String delUsers(Integer [] ids){ //參數名要和頁面中傳的參數名相同 for(Integer id:ids){ System.out.println(id); } //new UserDao().deleteUsers(ids); return "success"; } //附:也可以如下 @RequestMapping("/deleUser") public String delUsers(HttpServletRequest request){ String [] ids=request.getParameterValues("ids"); //new UserDao().deleteUsers(ids); return "success"; }
7) List 類型的數據綁定 (比如批量更新)
包裝類型
public class UserInfoCustomL { private List<UserInfo> userList; //生成get set }