SpringMVC 1.2

1、请求URL和方法的映射

@RequestMapping注解来进行URL和方法的映射

可能的情况:

①一个类里面,每个方法的URL,没有相同的部分,于是每个方法上面,都各自指定一个URL。

②一个类里面,所有的方法,前面部分都是一样的,比如:

/user/add、/user/list、/user/view、/user/update

此时可以在类上面使用 @RequestMapping(value=”/user”),此时方法上面就只需要:@RequestMapping(value=”add”)。

HTTP的请求方法:

GET  


POST  


DELETE 删除服务器的数据


PUT     新增数据


HEAD    只返回响应头

浏览器只能发送GET、POST请求,其他的请求浏览器无法直接发送。可以借助一些手段发送GET、POST之外的其他请求。

2、视图解析器

作用:简化返回的视图路径。在SpringMVC里面,支持多种视图,如JSP、xml

举个较常用的视图解析器,更多可查看Spring官方文档

①hello-servlet.xml

注意:如果使用UrlBasedViewResolver,需要加上jstl的jar包,否则抛出java.lang.ClassNotFoundException: javax.servlet.jsp.jstl.core.Config


在输入访问路径后,配置以上内容后会自动加上前缀/WEB-INF/content/,后缀.jsp

②控制器

web项目结构:


测试:



3、接收浏览器的参数

index1.jsp


①在SpringMVC里面接收请求参数,通过方法的参数传入的

i.参数和jsp页面传过来的一致


ii.参数和jsp页面传过来的不一致。需要加上@RequestParam注解。推荐无论是否相同都加上。


测试:


4、请求参数自动转换为Java对象

平时情况

①Employee.java


②index2.jsp

③EmployeeController.java

    @InitBinder注解的作用:任意的方法,如果使用了这个注解,就可以得到WebDataBinder对象,用于注册自定义转换器、验证器等。这个注解的方法在进行参数绑定之前执行一次。

PropertyEditor是属性编辑器的接口,它规定了将外部设置值转换为内部JavaBean属性值的转换接口方法

特殊情况

情况1:如果出现两个相同类型不同格式的对象

①Employee.java出现两个Date,但格式不同

public class Employee {

	private String name;
	// 默认SpringMVC基本上无法把String转换为Date,需要自定义转换器
	private Date birthday;
	private int age;
	private Date updateTime;

	//getter、setter

	@Override
	public String toString() {
		return "Employee [name=" + name + ", birthday=" + birthday + ", age=" + age + ", updateTime=" + updateTime
				+ "]";
	}
}
②EmployeeController.java

此处注意,必须要有一个指定字段,否则会有一个出错

@Controller
@RequestMapping("/employee")
public class EmployeeController {

	@InitBinder
	public void initBinder(WebDataBinder binder){
		binder.registerCustomEditor(Date.class, new PropertyEditorSupport(){
			// 把字符串转换为目标数据类型的对象
			// 转换以后,需要调用父类里面的setValue方法设置Java对象。
			@Override
			public void setAsText(String text) throws IllegalArgumentException {
				DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
				try {
					Date d = format.parse(text);
					super.setValue(d);
				} catch (ParseException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
		
		// 指定某个字段专用的转换器
		binder.registerCustomEditor(Date.class, "updateTime", new PropertyEditorSupport(){
			
			@Override
			public void setAsText(String text) throws IllegalArgumentException {
				DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				try {
					Date d = format.parse(text);
					super.setValue(d);
				} catch (ParseException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
	}
	
	@RequestMapping
	public String save(Employee e){
		System.out.println(e);
		return "/save.jsp";
	}

}
③测试:

情况2请求参数包含多个对象的时候

①index3.jsp

②Department.java

③DepartmentController.java

要通过 @InitBinder 指定对象的前缀

@Controller
@RequestMapping("/department")
public class DepartmentController {
	
	//要通过 @InitBinder 指定对象的前缀
	@InitBinder("employee")
	public void employee(WebDataBinder binder){
		binder.setFieldDefaultPrefix("employee.");
	}
	@InitBinder("dept")
	public void dept(WebDataBinder binder){
		binder.setFieldDefaultPrefix("department.");
	}
	
	@RequestMapping
	public String  save(@ModelAttribute("employee") Employee employee,@ModelAttribute("dept") Department department){
		System.out.println("------"+employee);
		System.out.println("------"+department);
		return "department/save";
	}
} 

④测试:



总结:

a.如果请求参数里面,只有一个对象的数据,只需要把对象的类型作为方法的参数即可,不需要任何的额外注解。

b.有一些参数不能正常转换为对象需要的数据,则要用 @InitBinder 注册自定义的转换器。

c.如果请求参数里面包含多个对象的数据,这些数据需要有【前缀】,并且每个对象,都要有一个对应的 @InitBinder 注解的方法。同时Action方法的参数需要使用@ModelAttribute 注解对应@InitBinder 的名字。

5、请求响应方式(导航)

①forward

直接返回一个jsp的路径,就会forward到jsp。可以结合ViewResolver来找到对应的JSP文件。

②redirect

i.使用 redirect: 开头。重定向到根目录下的a.jsp文件

ii.使用RedirectView。重定向到根目录下的a.jsp文件


③响应体

i.使用@ResponseBody注解方法,直接把方法的返回值作为内容返回给浏览器

测试:


ii.使用ResponseEntity对象返回,可以自定义返回的响应头、响应内容

测试:


6、

 ①获取请求头

 使用方法的参数来进行获取,获取的时候,在参数前面使用 @RequestHeader 注解


 ②.获取Cookie值


 ③.操作Session

 每个Controller只负责管理自己的session里面的值。Session是整个用户会话共享的,在Controller里面如果要把数据放入session里面,需要先在类上面使用 @SessionAttributes注解标明哪些对象要放入session里面,当方法执行完成以后,Spring调用session.setAttribute方法放入session。

 在Controller里面,通过Model、ModelAndView对象,把数据放到【模型】里面,在方法执行完成以后,检查【模型】里面的对象的名字,是否在@SessionAttributes注解里面,如果在则放入session。

i.通过Model传值给session

下面例子中key1,key2是没存进session的,因为@SessionAttributes注解没有表明

@Controller
@RequestMapping("/session")
@SessionAttributes({"key3","key4"})
public class TestSessionAction {
	
	// 通过Model传值给session
	@RequestMapping("/1")
	public String test1(Model model){	
		model.addAttribute("key1", "val1");
		model.addAttribute("key2", "val2");
		return "session";
	}
}

ii.通过ModelAndView传值给session

	@RequestMapping("/2")
	public ModelAndView test2(){	
		ModelAndView mv = new ModelAndView();
		mv.addObject("key3", "val3");
		mv.addObject("key4", "val4");
		mv.setViewName("session");
		return mv;
	}

iii.删除当前Controller存入session的对象

	@RequestMapping("/3")
	public String test3(SessionStatus status){	
    //Mark the current handler's session processing as complete,
    //allowing for cleanup of session attributes.	
		status.setComplete();
		return "session";
	}

7、Servlet API的使用

在任何的MVC框架里面,都不推荐直接使用ServletAPI,但是几乎所有的框架,都提供了使用Servlet API的方式。

Spring提供了两种使用Servlet API的方式

①在方法参数里面,直接使用 HttpServletRequest、HttpServletResponse等作为参数,Spring MVC会自动把对象传入进来。

	@RequestMapping("/1")
	public String test(HttpServletRequest req,HttpServletResponse resp){		
		req.setAttribute("key1", "val1");
       req.getSession().setAttribute("key1", "val1");
     System.out.println("--test1--");
		return "test";
	}

@RequestMapping("/3")
	public String test3(HttpSession session){
		String p = (String)session.getAttribute("key1");
		System.out.println("test3:"+p);
		return "test";
	}

②使用WebRequest、HttpSession的对象。Spring MVC为了避免直接使用Servlet API造成的不良影响、又能够提供完全的Servlet API调用的控制,所以封装了一个叫做WebRequest的对象,通过这个对象几乎能够完成所有的Servlet API的工作。

@RequestMapping("/2")
	public String test2(WebRequest weq){
		String p = weq.getParameter("key1");
		System.out.println(p);
		//通过WebRequest将属性放入,不能使用SessionStatus.setComplete()这种方法删除
		//只能使用WebRequest的removeAttribute
		weq.setAttribute("key2", "", WebRequest.SCOPE_REQUEST);
		// 从request里面删除对象
		weq.removeAttribute("key2", WebRequest.SCOPE_REQUEST);
		// session
		weq.setAttribute("yyy", "", WebRequest.SCOPE_SESSION);
		return "test";
	}

8、拦截器

拦截器配置在【-servlet.xml】文件里面,仅在当前模块里面有效。

所有的拦截器,都需要实现org.springframework.web.servlet.HandlerInterceptor,或者继承

org.springframework.web.servlet.handler.HandlerInterceptorAdapter

①hello-servlet.xml

<mvc:interceptors>
    <!-- hello模块全局拦截器 -->
    <bean class="cony.action.TestInterceptor" />
    <mvc:interceptor>
   <!--设置拦截路径 -->
  <mvc:mapping path="/a/2"/>
        <!-- 局部拦截器 -->
        <bean class="cony.action.TestInterceptor2"/>
    </mvc:interceptor>
</mvc:interceptors>
②TestInterceptor.java

public class TestInterceptor extends HandlerInterceptorAdapter {

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		System.out.println("afterCompletion");
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("postHandle");
	}

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		System.out.println("preHandle");
		// 返回true,后面的业务才会继续
		return true;
	}

}

③TestInterceptor2.java

public class TestInterceptor2  extends HandlerInterceptorAdapter{
	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		System.out.println("afterCompletion2");
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("postHandle2");
	}

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		System.out.println("preHandle2");
		// 返回true,后面的业务才会继续
		return true;
	}
}
④测试:

  i.

ii.可以看到局部拦截器先执行,然后才是全局拦截器

⑤拦截器方法说明

preHandle:每次进入拦截器,最先执行的方法。

如果这个方法返回false,不会继续执行后面的业务

postHandle:在进入方法、实际的业务方法执行完成以后,执行forward之前。

afterCompletion:整个请求完成的时候执行,完成forward之后执行

执行这个方法的时候,连jsp也已经执行完成。


猜你喜欢

转载自blog.csdn.net/ack_finding/article/details/79113072
1.2