本文主要是講解在Controller中的開發,主要的知識點有以下:javascript
@RequestMapping
詳解在SpringMVC的控制器中,若是沒有對編碼進行任何的操做,那麼獲取到的中文數據是亂碼!html
即便咱們在handle()方法中,使用request對象設置編碼也不行!緣由也很是簡單,咱們SpringMVC接收參數是經過控制器中的無參構造方法,再通過handle()方法的object對象來獲得具體的參數類型的。java
Struts2是使用攔截器來自動幫咱們完成中文亂碼的問題的。那麼SpringMVC做爲一個更增強大的框架,確定也有對應的方法來幫咱們完成中文亂碼問題!web
值得注意的是:該過濾編碼器只能解決POST的亂碼問題!ajax
咱們只須要在web.xml配置文件中設置過濾編碼器就好了!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>
複製代碼
咱們在快速入門的例子中使用的是XML配置的方式來使用SpringMVC的,SpringMVC也可以支持註解。【我的很是喜歡註解的方式】json
咱們在使用Action的時候,要麼繼承着AbstractCommandController類,要麼顯示使用註解Controller接口。當咱們使用了註解之後就不用顯示地繼承或實現任何類了!數組
使用@Controller這個註解,就代表這是一個SpringMVC的控制器!微信
@Controller
public class HelloAction {
}
複製代碼
固然了,如今Spring是不知道有這麼一個註解的,所以咱們須要在配置文件中配置掃描註解session
**值得注意的是:*在配置掃描路徑的時候,後面不要加.
否則掃描不了,我不知道學Struts2仍是其餘的地方時候,習慣加了.*,因而就搞了好久!
<!--掃描註解,後面不要加.*-->
<context:component-scan base-package="zhongfucheng"/>
複製代碼
在控制器中寫業務方法
@Controller
public class HelloAction {
/** * * @RequestMapping 表示只要是/hello.action的請求,就交由該方法處理。固然了.action能夠去掉 * @param model 它和ModelAndView相似,它這個Model就是把數據封裝到request對象中,咱們就能夠獲取出來 * @return 返回跳轉的頁面【真實路徑,就不用配置視圖解析器了】 * @throws Exception */
@RequestMapping(value="/hello.action")
public String hello(Model model) throws Exception{
System.out.println("HelloAction::hello()");
model.addAttribute("message","你好");
return "/index.jsp";
}
}
複製代碼
跳轉到index頁面,首頁獲得對應的值。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
這是個人首頁 <br>
${message}
</body>
</html>
複製代碼
固然了,基於註解和基於XML來開發SpringMVC,都是經過映射器、適配器和視圖解析器的。 只是映射器、適配器略有不一樣。可是都是能夠省略的!
<!-- 基於註解的映射器(可選) -->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<!-- 基於註解的適配器(可選) -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<!-- 視圖解析器(可選) -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"/>
複製代碼
更新:上邊的適配器和映射器只是Spring3.1版本以前使用的、3.1版本以後如今通常用如下的兩個
映射器:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
適配器:
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
複製代碼
固然了,這上面兩個配置也可使用<mvc:annotation-driven>
>替代註解處理器和適配器的配置。
@RequestMapping可以控制請求路徑和請求方式!
到目前爲止,咱們都是一個控制器寫一個業務方法,這確定是不合理的。咱們在Struts2中一個Action就對應多個業務方法了。那麼咱們在SpringMVC中又怎麼寫呢???
其實咱們能夠推理出來,@RequestMapping就是用於配置哪一個請求對應哪一個業務方法的!
public @interface RequestMapping {
String[] value() default {};
RequestMethod[] method() default {};
String[] params() default {};
String[] headers() default {};
}
複製代碼
當咱們請求hello.action的時候,處理的業務方法是hello().....當咱們請求bye.action的時候,處理的業務方法是bye()
@Controller
public class HelloAction {
/** * * @RequestMapping 表示只要是/hello.action的請求,就交由該方法處理。固然了.action能夠去掉 * @param model 它和ModelAndView相似,它這個Model就是把數據封裝到request對象中,咱們就能夠獲取出來 * @return 返回跳轉的頁面【真實路徑,就不用配置視圖解析器了】 * @throws Exception */
@RequestMapping(value="/hello.action")
public String hello(Model model) throws Exception{
System.out.println("HelloAction::hello()");
model.addAttribute("message","你好");
return "/index.jsp";
}
@RequestMapping(value = "/bye.action")
public String bye(Model model) throws Exception {
model.addAttribute("message","再見");
return "/index.jsp";
}
}
複製代碼
固然了,咱們在Struts2經常使用namespace來進行分模塊開發,在SpringMVC中咱們也能夠這樣幹,而且咱們又是使用的是@RequestMapping這個註解!
只要把@RequestMapping這個註解寫到類上面去,就表明了分模塊。
@Controller
//咱們知道,若是是value屬性上的註解,咱們能夠把value省略掉的
@RequestMapping("/zhongfucheng")
public class HelloAction {
/** * @param model 它和ModelAndView相似,它這個Model就是把數據封裝到request對象中,咱們就能夠獲取出來 * @return 返回跳轉的頁面【真實路徑,就不用配置視圖解析器了】 * @throws Exception * @RequestMapping 表示只要是/hello.action的請求,就交由該方法處理。固然了.action能夠去掉 */
@RequestMapping(value = "/hello.action")
public String hello(Model model) throws Exception {
System.out.println("HelloAction::hello()");
model.addAttribute("message", "你好");
return "/index.jsp";
}
@RequestMapping(value = "/bye.action")
public String bye(Model model) throws Exception {
model.addAttribute("message", "再見");
return "/index.jsp";
}
}
複製代碼
那麼咱們想要HelloAction該控制器處理咱們的請求,訪問的地址要麼是:http://localhost:8080/zhongfucheng/hello.action
,或者要麼是http://localhost:8080/zhongfucheng/bye.action
咱們若是想要限定某個業務控制方法,只容許GET或POST請求方式訪問。仍是經過@RequestMapping來實現。只要設定它的method屬性就好了!
@RequestMapping(value = "/bye.action",method = RequestMethod.POST)
public String bye(Model model) throws Exception {
model.addAttribute("message", "再見");
return "/index.jsp";
}
複製代碼
當我把業務方法的請求設置爲POST之後,我想要經過GET方式來訪問該業務方法。就行不通了!
咱們的業務方法除了能夠寫Model這個參數之外,若是有須要咱們還能夠寫request,response等傳統Servlet的參數。這是同樣可使用的....
可是呢,咱們並不建議使用傳統的web參數,由於會耦合
@RequestMapping(method=RequestMethod.POST,value="/register")
public String registerMethod(HttpServletRequest request,HttpServletResponse response) throws Exception{
//獲取用戶名和薪水
String username = request.getParameter("username");
String salary = request.getParameter("salary");
System.out.println("用戶註冊-->" + username + ":" + salary);
//綁定到session域對象中
request.getSession().setAttribute("username",username);
request.getSession().setAttribute("salary",salary);
//重定向/jsp/success.jsp頁面
//response.sendRedirect(request.getContextPath()+"/jsp/success.jsp");
//轉發/jsp/ok.jsp頁面
request.getRequestDispatcher("/jsp/ok.jsp").forward(request,response);
//轉發(提倡)
return "/jsp/success.jsp";
}
複製代碼
小細節:若是咱們的返回值是返回一個真實路徑,而咱們在程序中又使用了轉發或重定向。。。那麼具體跳轉的位置就是按咱們程序中跳轉的路徑爲準!
咱們在Struts2中收集web端帶過來的參數是在控制器中定義成員變量,該成員變量的名字與web端帶過來的名稱是要一致的...而且,給出該成員變量的set方法,那麼Struts2的攔截器就會幫咱們自動把web端帶過來的參數賦值給咱們的成員變量....
那麼在SpringMVC中是怎麼收集參數的呢????咱們SpringMVC是不可能跟Struts2同樣定義成員變量的,由於SpringMVC是單例的,而Struts2是多例的。所以SpringMVC是這樣乾的:
若是是普通參數的話,咱們直接在方法上寫上與web端帶過來名稱相同的參數就好了!
<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>編號</td>
<td><input type="text" name="id"></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="提交">
</td>
</tr>
</table>
</form>
複製代碼
@RequestMapping(value = "/hello.action")
public String hello(Model model, String username, int id) throws Exception {
System.out.println("用戶名是:" + username);
System.out.println("編號是:" + id);
model.addAttribute("message", "你好");
return "/index.jsp";
}
複製代碼
效果:
咱們處理表單的參數,若是表單帶過來的數據較多,咱們都是用JavaBean對其進行封裝的。那麼咱們在SpringMVC也是能夠這麼作的。
建立JavaBean,javaBean屬性與表單帶過來的名稱相同
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 + '\'' +
'}';
}
}
複製代碼
在業務方法參數上寫入Javabean
@RequestMapping(value = "/hello.action")
public String hello(Model model,User user) throws Exception {
System.out.println(user);
model.addAttribute("message", "你好");
return "/index.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>愛好</td>
<td><input type="checkbox" name="hobby" value="1">籃球</td>
<td><input type="checkbox" name="hobby" value="2">足球</td>
<td><input type="checkbox" name="hobby" value="3">排球</td>
<td><input type="checkbox" name="hobby" value="4">羽毛球</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="提交">
</td>
</tr>
</table>
</form>
複製代碼
業務方法獲取參數
@RequestMapping(value = "/hello.action")
public String hello(Model model,int[] hobby) throws Exception {
for (int i : hobby) {
System.out.println("喜歡運動的編號是:" + i);
}
model.addAttribute("message", "你好");
return "/index.jsp";
}
複製代碼
效果:
List<JavaBean>
集合咱們在Spring的業務方法中是不能夠用List這樣的參數來接收的,SpringMVC給了咱們另外一種方案!
咱們使用一個JavaBean把集合封裝起來,給出對應的set和get方法。那麼咱們在接收參數的時候,接收的是JavaBean
/** * 封裝多個Emp的對象 * @author AdminTC */
public class Bean {
private List<Emp> empList = new ArrayList<Emp>();
public Bean(){}
public List<Emp> getEmpList() {
return empList;
}
public void setEmpList(List<Emp> empList) {
this.empList = empList;
}
}
複製代碼
業務方法接收JavaBean對象
/** * 批量添加員工 */
@RequestMapping(value="/addAll",method=RequestMethod.POST)
public String addAll(Model model,Bean bean) throws Exception{
for(Emp emp:bean.getEmpList()){
System.out.println(emp.getUsername()+":"+emp.getSalary());
}
model.addAttribute("message","批量增長員工成功");
return "/jsp/ok.jsp";
}
複製代碼
在JSP頁面直接寫上empList[下表].
<form action="${pageContext.request.contextPath}/emp/addAll.action" method="POST">
<table border="2" align="center">
<caption><h2>批量註冊員工</h2></caption>
<tr>
<td><input type="text" name="empList[0].username" value="哈哈"/></td>
<td><input type="text" name="empList[0].salary" value="7000"/></td>
</tr>
<tr>
<td><input type="text" name="empList[1].username" value="呵呵"/></td>
<td><input type="text" name="empList[1].salary" value="7500"/></td>
</tr>
<tr>
<td><input type="text" name="empList[2].username" value="班長"/></td>
<td><input type="text" name="empList[2].salary" value="8000"/></td>
</tr>
<tr>
<td><input type="text" name="empList[3].username" value="鍵狀哥"/></td>
<td><input type="text" name="empList[3].salary" value="8000"/></td>
</tr>
<tr>
<td><input type="text" name="empList[4].username" value="綠同窗"/></td>
<td><input type="text" name="empList[4].salary" value="9000"/></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="批量註冊"/>
</td>
</tr>
</table>
</form>
複製代碼
其實這種方法看起來也沒有那麼難理解,咱們就是向上封裝了一層【與接收普通的JavaBean相似的】。
咱們有可能在JSP頁面上即有User模型的數據要收集,又有Emp模型的數據要收集....而且User模型的屬性和Emp模型的屬性如出一轍....此時咱們該怎麼辦呢???
咱們也是能夠在User模型和Emp模型上向上抽象出一個Bean,該Bean有Emp和User對象
/** * 封裝User和Admin的對象 * @author AdminTC */
public class Bean {
private User user;
private Admin admin;
public Bean(){}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Admin getAdmin() {
return admin;
}
public void setAdmin(Admin admin) {
this.admin = admin;
}
}
複製代碼
在JSP頁面收集的時候,給出對應的類型就好了。
<form action="${pageContext.request.contextPath}/person/register.action" method="POST">
<table border="2" align="center">
<tr>
<th>姓名</th>
<td><input type="text" name="user.username" value="${user.username}"/></td>
</tr>
<tr>
<th>月薪</th>
<td><input type="text" name="user.salary" value="${user.salary}"></td>
</tr>
<tr>
<th>入職時間</th>
<td><input type="text" name="user.hiredate" value='<fmt:formatDate value="${user.hiredate}" type="date" dateStyle="default"/>'/></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="普通用戶註冊" style="width:111px"/>
</td>
</tr>
</table>
</form>
複製代碼
咱們在Struts2中,若是web端傳過來的字符串類型是yyyy-mm-dd hh:MM:ss這種類型的話,那麼Struts2默認是能夠自動解析成日期的,若是是別的字符串類型的話,Struts2是不能自動解析的。要麼使用自定義轉換器來解析,要麼就本身使用Java程序來解析....
而在SpringMVC中,即便是yyyy-mm-dd hh:MM:ss這種類型SpringMVC也是不能自動幫咱們解析的。咱們看以下的例子:
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>出生日期</td>
<td><input type="text" name="date" value="1996-05-24"></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="提交">
</td>
</tr>
</table>
</form>
複製代碼
User對象定義Date成員變量接收
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
複製代碼
業務方法獲取Date值
@RequestMapping(value = "/hello.action")
public String hello(Model model, User user) throws Exception {
System.out.println(user.getUsername() + "的出生日期是:" + user.getDate());
model.addAttribute("message", "你好");
return "/index.jsp";
}
複製代碼
結果出問題了,SpringMVC不支持這種類型的參數:
如今問題就拋出來了,那咱們要怎麼解決呢????
SpringMVC給出相似於Struts2類型轉換器這麼一個方法給咱們使用:若是咱們使用的是繼承AbstractCommandController類來進行開發的話,咱們就能夠重寫initBinder()方法了....
具體的實現是這樣子的:
@Override
protected void initBinder(HttpServletRequest request,ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(Date.class,new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
}
複製代碼
那咱們如今用的是註解的方式來進行開發,是沒有重寫方法的。所以咱們須要用到的是一個註解,代表我要重寫該方法!
@InitBinder
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(
Date.class,
new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
}
複製代碼
再次訪問:
值得注意的是:若是咱們使用的是Oracle插入時間的話,那麼咱們在SQL語句就要寫TimeStrap時間戳插入進去,不然就行不通!
咱們通常作開發的時候,常常編輯完數據就返回到顯示列表中。咱們在Struts2是使用配置文件進行重定向或轉發的:
而咱們的SpringMVC就很是簡單了,只要在跳轉前寫上關鍵字就好了!
public String hello(Model model, User user) throws Exception {
System.out.println(user.getUsername() + "的出生日期是:" + user.getDate());
model.addAttribute("message", user.getDate());
return "redirect:/index.jsp";
}
複製代碼
以此類推,若是是想要再次請求的話,那麼咱們只要寫上對應的請求路徑就好了!
@RequestMapping(value = "/hello.action")
public String hello(Model model, User user) throws Exception {
return "redirect:/bye.action";
}
@RequestMapping("/bye.action")
public String bye() throws Exception {
System.out.println("我進來了bye方法");
return "/index.jsp";
}
複製代碼
回顧一下Struts2返回JSON文本是怎麼操做的:
那麼咱們在SpringMVC又怎麼操做呢???
導入兩個JSON開發包
在要返回JSON的業務方法上給上註解:
@RequestMapping(value = "/hello.action")
public
@ResponseBody
User hello() throws Exception {
User user = new User("1", "zhongfucheng");
return user;
}
複製代碼
配置JSON適配器
<!-- 1)導入jackson-core-asl-1.9.11.jar和jackson-mapper-asl-1.9.11.jar 2)在業務方法的返回值和權限之間使用@ResponseBody註解表示返回值對象須要轉成JSON文本 3)在spring.xml配置文件中編寫以下代碼: -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
</list>
</property>
</bean>
複製代碼
測試的JSP
<input type="button" value="Emp轉JSON"/><p>
<input type="button" value="List<Emp>轉JSON"/><p>
<input type="button" value="Map<String,Object>轉JSON"/><p>
<!-- Map<String,Object>轉JSON -->
<script type="text/javascript"> $(":button:first").click(function(){ var url = "${pageContext.request.contextPath}/hello.action"; var sendData = null; $.post(url,sendData,function(backData,textStaut,ajax){ alert(ajax.responseText); }); }); </script>
複製代碼
測試:
Map測試:
@RequestMapping(value = "/hello.action")
public
@ResponseBody
Map hello() throws Exception {
Map map = new HashMap();
User user = new User("1", "zhongfucheng");
User user2 = new User("12", "zhongfucheng2");
map.put("total", user);
map.put("rows", user2);
return map;
}
複製代碼
更新------------------------------------------------------------------
若是傳遞進來的數據就是JSON格式的話,咱們咱們須要使用到另一個註解@RequestBody
,將請求的json數據轉成java對象
若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠關注微信公衆號:Java3y