2022-04-21 14:16:35
# springmvc笔记
springmvc(笔记—传播智客 苗润土)
1.前端处理器 dispathcherServlet
2.处理器映射器 handlerMapping
3.处理器适配器 handlerAdapter
4.视图解析器 viewResoler
1
2
3
4
5
2
3
4
5
# 1、配置
新建web项目,导入jar包
web.xml配置
<!-- springmvc前端控制器 dispathcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
springmvc.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:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd ">
<!-- 处理器映射器 handlerMapping:根据url找到请求的handler(内部只包装一个method)。 多个处理器映射器可以共存 -->
<!-- BeanNameUrlHandlerMapping 将bean的name当成action的url,根据url找到请求的handler及handler方法 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- SimpleUrlHandlerMapping 将所有的url集中配置在处 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<!-- prop的值 hello_controller是bean的id -->
<prop key="/hello1.action">hello_controller</prop>
<prop key="/hello2.action">hello_controller2</prop>
</props>
</property>
</bean>
<!-- 处理器适配器handlerAdapter:根据handler的规则来执行。实现的接口不一样,执行不一样 -->
<!-- 凡实现Controller接口的类都当成SimpleControllerHandlerAdapter执行的对象 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!-- 另 一个处理适配置器 所有实现HttpRequestHandler接口的由该适配置器执行 -->
<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
<!-- 视图解析器 viewResolvew -->
<!-- 解析jsp视图,默认支持jstl标签-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- jsq文件前缀 -->
<property name="prefix" value="/WEB-INF/jsp/"></property>
<!-- jsq文件后缀缀 -->
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 编写action的配置 -->
<bean name="/hello.action" id="hello_controller" class="com.test.springmvc.action.HelloWorld"></bean>
<bean id="hello_controller2" class="com.test.springmvc.action.HelloWorld2"></bean>
</beans>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
handler
public class HelloWorld implements Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest arg0,
HttpServletResponse arg1) throws Exception {
// TODO Auto-generated method stub
ModelAndView modelAndView=new ModelAndView();
String s="Controller ModelAndView";
modelAndView.addObject("message", s);
//传到对应的jsp页面.springmvc.xml需要配置前缀,后缀
modelAndView.setViewName("helloWorld");
return modelAndView;
}
jsp
${message}
命令控制器AbstractCommandController:一个请求只有一个方法。且只能定义一个命令对象。
需要指定class。重写日期格式。
public class AddSubmitStudent extends AbstractCommandController{
public AddSubmitStudent(){
this.setCommandClass(Student.class);
}
@Override
protected ModelAndView handle(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, BindException arg3)
throws Exception {
// TODO Auto-generated method stub
ModelAndView modelAndView=new ModelAndView();
Student s=(Student)arg2;
modelAndView.addObject("student_name", s.getName());
modelAndView.addObject("student_id", s.getId());
modelAndView.addObject("student_birthday", s.getBirthday());
System.out.println(s);
modelAndView.setViewName("success");
return modelAndView;
}
@Override
protected void initBinder(HttpServletRequest request,
ServletRequestDataBinder binder) throws Exception {
// TODO Auto-generated method stub
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
web.xml
<!-- post乱码过虑器 -->
<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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 2、说明
1、处理器映射器
第一种:BeanNameUrlHandlerMapping,将bean的name当成action的url
第二种:SimpleUrlHandlerMapping,将bean的url集成在一处进行配置
2、处理器适配置器
第一种:SimpleControllerHandlerAdapter,凡是实现controller接口的bean由此适配器进行执行
第二种:HttpRequestHandlerAdapter,凡是实现HttpRequestHandler接口的bean,由此适配器执行
3、命令控制器AbstractCommandController
框架提供一个命令控制器的类
自定义action时需要继承抽象的命令控制器的类
缺点:一个请求在此类只有一方法去处理,且只能定义一个命令对象。
问题:
日期数据的格式化
//日期格式数据在绑定
@Override
protected void initBinder(HttpServletRequest request,
ServletRequestDataBinder binder) throws Exception {
//指定日期类型及日期数据的格式
//日期类型要和student类的birthday一致
binder.registerCustomEditor(Date.class, new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
}
post乱码问题
在web.xml中添加过虑器.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
springmvc注解
1、使用eclipse创建web工程
2、加入springmvc的jar包(spring的jar及springmvc模块的jar加入)
3、配置前端 控制器
需要在web.xml中配置
4、配置处理器映射器
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
5、配置处理器适配器
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
6、组件扫描
扫描的标记@Controller注解的类,通过组件扫描将Controller注解的类发现,注入到spring容器。
可以省略spring配置文件配置bean
7.handler
@Controller
public class StudentAction {
@RequestMapping(value="/queryStudent")
public String queryStudent(Model model){
Student s1=new Student();
s1.setName("张三");
s1.setId(11);
s1.setBirthday(new Date());
Student s2=new Student();
s2.setName("李四");
s2.setId(22);
s2.setBirthday(new Date());
List<Student> list=new ArrayList<Student>();
list.add(s1);
list.add(s2);
model.addAttribute("studentList", list);
//返回的是queryStudent.jsp页面
return "queryStudent";
}
8.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
springmvc注解 <br>
<c:forEach items="${studentList}" var="s">
${s.name}--${s.id }--${s.birthday } <br>
</c:forEach>
http://localhost:8080/springmvc_04_Annotation/queryStudent.action
根路径
handler
@Controller
@RequestMapping("/user") //根路径
public class StudentAction {
@RequestMapping(value="/queryStudent")
public String queryStudent(Model model){
jsp
<form action="${pageContext.request.contextPath }/user/editStudentSubmit.action" method="post">
http://localhost:8080/springmvc_04_Annotation/user/queryStudent.action
url占位符
handler
@RequestMapping("/editStudent/{groupid}/{id}")
public String editStudent(Model model,@PathVariable String groupid,@PathVariable Integer id){
jsp
<a href="user/editStudent/${s.groupid }/${s.id }.action">修改</a>
<a href="${pageContext.request.contextPath }/user/editStudent/${s.groupid }/${s.id }.action">修改url</a>
/springmvc_04_Annotation/WebContent/WEB-INF/jsp/editStudent.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<form action="${pageContext.request.contextPath }/user/editStudentSubmit.action" method="post">
<table width="60%" border="1px">
<tr>
<td>id</td>
<td><input type="text" value="${student.id }" name="id" readonly="readonly"></td>
</tr>
<tr>
<td>姓名</td>
<td><input type="text" value="${student.name }" name="name"></td>
</tr>
<tr>
<td>性别</td>
<td>
男<input type="radio" name="sex" value="1" checked='<c:if test="${ student.sex=='1'}">checked</c:if>' />
女<input type="radio" name="sex" value="2" checked='<c:if test="${ student.sex=='2'}">checked</c:if>' />
</td>
</tr>
<tr>
<td>类型</td>
<td>
<select name="groupid">
<option value="1" <c:if test="${student.groupid=='1'}"> selected</c:if> >三好学生 </option>
<option value="2" <c:if test="${student.groupid=='2'}"> selected</c:if> >一般学生 </option>
</select>
</td>
</tr>
<tr>
<td>出生日期</td>
<td><input type="text" value="<fmt:formatDate value="${student.birthday }" pattern="yyyy-MM-dd"/>" name="birthday"></td>
</tr>
</table>
<input type="submit" value="修改">
</form>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# 3、Pojo对象
限定GET方法
@RequestMapping(method = RequestMethod.GET)
如果通过Post访问则报错:
HTTP Status 405 - Request method 'POST' not supported
例如:
@RequestMapping(value="/useredit/{userid}",method=RequestMethod.GET)
限定POST方法
@RequestMapping(method = RequestMethod.POST)
GET和POST都可以
@RequestMapping(method={RequestMethod.GET,RequestMethod.POST})
Pojo对象
页面上以pojo对象中属性名称命名:
将pojo对象中的属性名于传递进来的属性名对应,如果传进来的参数名称和对象中的属性名称一致则将参数值设置在pojo对象中
页面定义如下;
<input type="text" name="age"/>
<input type="text" name="birthday"/>
Contrller方法定义如下:
public String useraddsubmit(Model model,User user)throws Exception{
System.out.println(user);
}
页面上以pojo对象名点属性名命名:
如果采用类似struts中对象.属性的方式命名,需要将pojo对象作为一个包装对象的属性,action中以该包装对象作为形参。
包装对象定义如下:
Public class UserVo {
private User user;
public User getUser() {
return user;
}
Public void setUser(User user) {
this.user = user;
}
}
页面定义:
<input type="text" name="user.age" />
<input type="text" name="user.birthday" />
Controller方法定义如下:
public String useraddsubmit(Model model,UserVo userVo)throws Exception{
System.out.println(userVo.getUser());
}
Map
在包装类中定义Map对象,并添加get/set方法,action使用包装对象接收。
包装类中定义Map对象如下:
Public class UserVo {
private Map<String, Object>studentinfo = new HashMap<String, Object>();
//get/set方法..
}
页面定义如下:
<tr>
<td>学生信息:</td>
<td>
姓名:<inputtype="text"name="studentinfo['name']"/>
年龄:<inputtype="text"name="studentinfo['age']"/>
.. .. ..
</td>
</tr>
Contrller方法定义如下:
public String useraddsubmit(Model model,UserVo userVo)throws Exception{
System.out.println(userVo.getStudentinfo());
}
List
与map类似,使用包装对象
public class UserVo {
private Student student;
private Map<String,Object> studentinfo=new HashMap<String,Object>();
private List<StudentScore> scores=new ArrayList<StudentScore>();
<tr>
<td>课程名称:<input type="text" name="scores[0].courename"></td>
<td>课程分数:<input type="text" name="scores[0].score" ></td>
</tr>
<tr>
<td>课程名称:<input type="text" name="scores[1].courename"></td>
<td>课程分数:<input type="text" name="scores[1].score" ></td>
</tr>
字符串数组接收数据
@RequestMapping("/deleteStudents")
public String deleteStudents(String[] deleteIds){
System.out.println("使用字符串数组接收数据:");
for(String id : deleteIds){
System.out.print(id+" ");
}
return "success";
}
<form action="${pageContext.request.contextPath }/user/deleteStudents.action" method="post">
<input type="submit" value="批量删除">
<c:forEach items="${studentList}" var="s">
<tr>
<td>
<input type="checkbox" name="deleteIds" value="${s.id }">
</td>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
@RequestParam绑定单个请求参数
value:参数名字,即入参的请求参数名字,如value=“studentid”表示请求的参数区中的名字为studentid的参数的值将传入;
required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报400错误码;
defaultValue:默认值,表示如果请求中没有同名参数时的默认值
定义如下:
public String userlist(
@RequestParam(defaultValue="2",value="group",required=true) String groupid) {
}
形参名称为groupid,但是这里使用value="group"限定参数名为group,所以页面传递参数的名必须为group。
这里通过required=true限定groupid参数为必需传递,如果不传递则报400错误,由于使用了defaultvalue=”2”默认值即使不传group参数它的值为”2”,所以页面不传递group也不会报错,如果去掉defaultvalue=”2”且定义required=true则如果页面不传递group则会报错。
redirect forward
return "redirect:queryStudent.action"; //重新产生request。URL变化
return "forward:queryStudent.action"; //原来的request,url不变
json请求与响应
@Controller
public class JsonTest {
@RequestMapping("/jsonRequest")
public @ResponseBody Student jsonRequest(@RequestBody Student student){
//请求json响应json
//@RequestBody json数据转换为对象
System.out.println(student);
//由于使用@ResponseBody注解,所以student对象自动转换为json输出
return student;
}
@RequestMapping("/jsonResponse")
public @ResponseBody Student jsonResponse(Student student){
//请求key/value响应json
System.out.println(student);
return student;
}
function requestJson(){
//请求为json数据
$.ajax({
url:"jsonRequest.action",
type:"post",
data:'{"name":"张三","id":"11"}',
contentType:'application/json;charset=utf-8',
success:function(data){
alert(data.name);
}
});
}
function requestKV(){
//请求为key/value数据
$.ajax({
url:"jsonResponse.action",
type:"post",
data:"name=李四&id=22",
success:function(data){
alert(data.name);
}
});
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# 4、拦截器
preHandle按拦截器定义顺序调用
postHandler按拦截器定义逆序调用
afterCompletion按拦截器定义逆序调用
postHandler在拦截器链内所有拦截器返成功调用
afterCompletion只有preHandle返回true才调用
用户登陆拦截
<!-- 拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean class="com.test.springmvc.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object arg2) throws Exception {
// TODO Auto-generated method stub
HttpSession session=request.getSession();
Student s=(Student) session.getAttribute("userinfo");
String u=request.getRequestURI();
if(u.indexOf("loginSubmit.action")>=0){
return true;
}
if(s!=null){
return true;
}
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package cn.itcast.springmvc.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import cn.itcast.springmvc.pojo.Student;
public class LoginInterceptor implements HandlerInterceptor {
/**
* 此方法是在进行handler方法之前执行
* arg2:要执行的handler
* 场景:用户权限的拦截
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object arg2) throws Exception {
HttpSession session = request.getSession();
//判断session中是否存在用户,存储表示用户已登录
Student student = (Student)session.getAttribute("userinfo");
if(student!=null){
//表示session存在,用户已登录
//放行
return true;
}
//判断请求的地址是否公开地址(不需要登录就可以访问的地址)
String url = request.getRequestURI();
if(url.indexOf("loginsubmit.action")>=0){
//是公开的地址,放行
return true;
}
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
//判断用户的session是否存在,如果不存在跳转到登录页面
//如果存在就放行
return false;
}
/**
* 此方法是在执行handler完毕,返回modenAndview之前执行
* 场景:对ModelAndView进行修改,比如统一添加页面导航(页面所需要的公用数据)
*/
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
}
/**
* 此方法是在执行handler完毕,且返回ModelAndView之后执行
* 场景:在这里记录执行的时间,并且在preHandle方法中也记录执行的开始时间,统一action执行时间,完成执行性能监视
* 场景:统一在这里进行日志记录
* 场景:统一进行异常处理
*/
@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72