2022-04-21 14:16:35

# springmvc笔记


springmvc(笔记—传播智客 苗润土)
1.前端处理器  dispathcherServlet
2.处理器映射器  handlerMapping
3.处理器适配器  handlerAdapter
4.视图解析器    viewResoler
1
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
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
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、说明

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
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

# 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
@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

# 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
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