springMVC的详解
一,springmvc注解特性
1.@Controller 控制器定义
在 spring 3.0 中,通过@controller 标注即可将 class 定义为一个 controller 类。为使 spring 能找到定义为 controller 的 bean,需要在 spring-context 配置文件中增加如下
定义:<context:component-scan base-package="com.shsxt.controller"/>
注:实际上,使用@component,也可以起到@Controller 同样的作用。
2.@RequestMapping
在类前面定义,则将 url 和类绑定。
在方法前面定义,则将 url 和类的方法绑定
下面的代码有两个注解,一个是在方法上,一个是在类上
所以访问路径变为 站点名/hello/hello,所以我的项目路径变为 localhost:8080/mvc/hello/hello
@Controller @RequestMapping("hello") public class HelloController { @RequestMapping("hello") public String hello(){ return "index.jsp"; }
二,参数绑定
请求参数到处理器功能处理方法的方法参数上的绑定,对于参数绑定非常灵活
1)字符串类型和基本数据类型 的绑定
前台传入一个参数,在后台的方法中可以通过定义形参来接收参数
controller层的部分代码
@RequestMapping("hello05") public String hell05(String a, Model model){ model.addAttribute("a",a); System.out.println(a); return "hello05"; }
jsp页面代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> 我是hello05 <hr> a=${a} </body> </html>
url地址: localhost:8080/mvc/hello05?a=123,页面效果如下:
2)数组类型
controller的代码
@RequestMapping("hello09") public String hello09(Integer[] ids){ for (Integer id:ids ) { System.out.print(id); } return "hello09"; }
3)po类型
controller的部分代码
@RequestMapping("hello10") public String hello10(User user){ System.out.println(user); return "hello09.jsp"; }
User的实体类
import java.util.ArrayList; import java.util.List; import java.util.Set; public class User { private Integer userid; private String username; private String userpwd; private List<Phone> phones; public Integer getUserid() { return userid; } public void setUserid(Integer userid) { this.userid = userid; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getUserpwd() { return userpwd; } public void setUserpwd(String userpwd) { this.userpwd = userpwd; } public List<Phone> getPhones() { return phones; } public void setPhones(List<Phone> list) { this.phones = list; } @Override public String toString() { return "User{" + "userid=" + userid + ", username='" + username + '\'' + ", userpwd='" + userpwd + '\'' + ", phones=" + phones + '}'; } }
4)list类型
此时 user 实体需要定义 list 属性,还需要一个Phone的实体类
phone实体类
package com.shsxt.po; public class Phone { private Integer number; public Integer getNumber() { return number; } public void setNumber(Integer number) { this.number = number; } @Override public String toString() { return "Phone{" + "number=" + number + '}'; } }
jsp页面的代码,代码的name的phones必须和Use字段中phones一样
<form action="hello11" method="post"> <input name="phones[0].number" /> <input name="phones[1].number" /> <button type="submit"> 提交</button> </form> </body> </html>
5)set类型的定义
set 和 List 类似,也需要绑定在对象上,而不能直接写在 Controller 方法的参数中。但是,绑定 Set 数据时,必须先在 Set 对象中 add 相应的数量的模型对象。 无序存储的原因
jsp页面
6)Map 最为灵活,它也需要绑定在对象上,而不能直接写在 Controller 方法的参数中。
三.@SessionAttributes注解
用于声明 session 级别存储的属性,放置在处理器类上
@Controller @SessionAttributes("username") public class IndexController { @RequestMapping("view01") public ModelAndView view01(String username) { ModelAndView modelAndView =new ModelAndView(); modelAndView.addObject("username",username); modelAndView.setViewName("view01.jsp"); return modelAndView; }
jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
我是用view01
${sessionScope.username}
</body>
</html>
用HttpServletRequest获取session来设置属性以及通过HttpSession来设置属性也可以
四,请求转发与重定向的问题
Springmvc 默认采用服务器内部转发的形式展示页面信息。同样也支持重定向页面。
1)重定向jsp页面
controller的代码
@Controller public class RedirectController { @RequestMapping("redirect") public String redirect(){ return "redirect:r1.jsp?a=1&b=2"; }
jsp代码,重定向的参数用${param.x}来获取,另外注意重定向页面需要放到webapp的根目录下,因为web.xml中配置url-pattern是可以放行webapp目录下的jsp ,配置成/*就统统都不放行了.
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> hello mvc ${param.a} <hr> ${param.b} </body> </html>
以上的重定向是可以的,但是有一个问题,不能解决中文乱码,看下面的实例
controller代码
@RequestMapping("redirect02") public String redirect02(RedirectAttributes attr){ attr.addAttribute("a",1); attr.addAttribute("b","上海"); return "redirect:r1.jsp?a=1&b=2"; }
可以使用modelAndView进行重定向,下面的两个实例效果是一样的
@RequestMapping("redirect07")
public ModelAndView queryView4(RedirectAttributes attr){
ModelAndView mv=new ModelAndView();
attr.addAttribute("a", "sxt");
attr.addAttribute("b", "尚学堂");
mv.setViewName("redirect:v1.jsp");
return mv;
}
@RequestMapping("redirect08") public ModelAndView redirect08(){ ModelAndView modelAndView =new ModelAndView(); modelAndView.addObject("a","shsxt"); modelAndView.addObject("b","尚学堂"); modelAndView.setViewName("redirect:r1.jsp"); System.out.println("重定向..."); return modelAndView; }
还可以重定向到controller,通过string,还可以通过ModelAndView
@RequestMapping("redirect04") public String redirect04(RedirectAttributes attr){ return "redirect:/redirect05"; } @RequestMapping("redirect05") public String redirect05(RedirectAttributes attr){ return "r2.jsp"; }
请求转发
@RequestMapping("redirect06") public String redirect06(){ return "forward:redirect07"; } @RequestMapping("redirect07") public String redirect07(){ return "r2.jsp"; }
四,获取request和response的对象
对于我们的方法默认方法的参数是空的,这时候要想获取 request,response 对象如何获取?
public ModelAndView queryUser(HttpServletRequest request,HttpServletResponse response){
String userName= request.getParameter("userName");
ModelAndView mv=new ModelAndView();
mv.addObject("userName", userName);
mv.setViewName("request");
return mv;
}
五,SpringMvc 之 Json 数据开发
@ResponseBody
该注解用于将 Controller 的方法返回的对象,通过适当的 HttpMessageConverter转换为指定格式后,写入到 Response 对象的 body 数据区。
返回的数据不是 html 标签的页面,而是其他某种格式的数据时(如 json、xml 等)使用(通常用于 ajax 请求)
@RequestBody
该注解用于读取 Request 请求的 body 部分数据,使用系统默认配置的HttpMessageConverter 进行解析,然后把相应的数据绑定到要返回的对象上 ,再把
HttpMessageConverter 返回的对象数据绑定到 controller 中方法的参数上Json 数据使用好处,Json 在企业开发中已经作为通用的接口参数类型,在页面(客户端)解析很方便。
SpringMvc 对于 json 提供了良好的支持,这里需要修改相关配置,添加 json 数据支持
1),添加json依赖jar包
dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.7.0</version> </dependency>
2)2.修改 servlet-context.xml 添加 json 转换器配置
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"> </bean> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" /> </list> </property> </bean>
controller层代码
@Controller @RequestMapping("user") public class JsonController { @RequestMapping("queryuser") @ResponseBody public User json(Integer id){ User user=new User(); user.setUserid(id); user.setUsername("liuqingfeng"); user.setUserpwd("hello springmvc"); return user; } }
六,拦截器
SpringMVC 中的 Interceptor 拦截器也是相当重要和相当有用的,它的主要作用是拦截用户的请求并进行相应的处理。比如通过它来进行权限验证,或者是来判断
用户是否登陆等操作。对于 springmvc 拦截器的定义方式有两种方式
1. 实现接口:org.springframework.web.servlet.HandlerInterceptor
2. 继承适配器org.springframework.web.servle t.handler.HandlerInterceptorAdapter
实现
package com.shsxt.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class MyInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("01,prehandle"); System.out.println(handler); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("01,posthandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("01,aftercompletion"); } }
继承
public class myInterceptor02 extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("02,prehandle"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("02,posthandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("02.afterCompletion"); } }
写完拦截器的代码写完之后需要在配置文件中进行配置
配置方式一:
<mvc:interceptors> <!-- 使用 bean 定义一个 Interceptor 直接定义在 mvc:interceptors 根下面的 Interceptor 将拦截所有的请求 --> <bean class="com.shsxt.interceptors.MyInterceptor" /> </mvc:interceptors>
配置方式二:
<mvc:interceptors>
<!-- 定义在 mvc:interceptor 下面 拦截所有 test 地址开头的请求-->
<mvc:interceptor>
<mvc:mapping path="/test/*.do" />
<bean class="com.shsxt.interceptors.MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
多个拦截器配置( 多个拦截器组成一个拦截器链 ,栈式结构 123 321 退出 ):
下面的两个拦截器组成了一个拦截器的链
<mvc:interceptors> <bean class="com.shsxt.interceptor.myInterceptor02"></bean> </mvc:interceptors> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/user/*"/> <bean class="com.shsxt.interceptor.MyInterceptor"></bean> </mvc:interceptor> </mvc:interceptors>
七,springMVC文件上传
1)Pom 文件修改 添加 commons-fileupload
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.2</version> </dependency>
2)配置文件添加
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize">
<value>104857600</value>
</property>
<property name="maxInMemorySize">
<value>4096</value>
</property>
</bean>
controller的代码
import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; import javax.servlet.http.HttpServletRequest; import java.io.File; @Controller public class uploadController { @RequestMapping("upload") public String uploadFile(HttpServletRequest request, Model model){ MultipartHttpServletRequest muli=(MultipartHttpServletRequest)request; MultipartFile file=muli.getFile("file");//参数名 if(file!=null && !file.isEmpty()){ String filename=file.getOriginalFilename();//文件名 String path=request.getSession().getServletContext().getRealPath("upload");//存储路径 try{ file.transferTo(new File(path,filename)); }catch(Exception e){ e.printStackTrace(); model.addAttribute("msg","上传失败"); } model.addAttribute("msg","上传成功"); } return "result.jsp"; } @RequestMapping("file") public String file(){ return "file.jsp"; } }
jsp页面代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <form action="upload" method="post" enctype="multipart/form-data"> <input type="file" name="file"> <button type="submit" >提交</button> </form> </body> </html>
七.ssm框架集成环境搭建
https://github.com/liuqingfeng123456789?tab=repositories
八,SpringMvc 实现 RestFul 服务
Restful 风格的 API 是一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风
格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
在 Restful 风格中,用户请求的 url 使用同一个 url 而用请求方式:get,post,delete,put...等方式对请求的处理方法进行区分,这样可以在前后台分离式的
开发中使得前端开发人员不会对请求的资源地址产生混淆和大量的检查方法名的麻烦,形成一个统一的接口。
在 Restful 风格中,现有规定如下:
GET(SELECT):从服务器查询,可以在服务器通过请求的参数区分查询的
方式。
POST(CREATE):在服务器端新建一个资源,调用 insert 操作。
PUT(UPDATE):在服务器端更新资源,调用 update 操作。
PATCH(UPDATE):在服务器端更新资源(客户端提供改变的属性)。(目前
jdk7 未实现,tomcat7 不支持)。
DELETE(DELETE):从服务器端删除资源,调用 delete 语句。
Spring Mvc Restl ful 风格 l url 配置 实现
springmvc的resturl是通过@RequestMapping 及@PathVariable annotation提供的,通过如@RequestMapping(value="/blog /{id}",method=RequestMethod.DELETE)
即可处理/blog/1 的 delete 请求.
Get 请求配置
没有配置之前的url
localhost:8080/ssm/user?id=1,get,post,delete都可以
@Controller public class UserContorller { @Resource public UserService userService; @RequestMapping(value="query/{id}",method = RequestMethod.GET) /*@RequestMapping("query")*/ @ResponseBody public User queryById(@PathVariable Integer id) throws Exception { /*int i=1/0;*/ /*if(true){ throw new ParamException("参数异常"); }*/ return userService.queryById(id); } }
配置get之后的url是
localhost:8080/ssm/user/1 且只能是get请求
九,SpringMVC 全局异常处理
SpringMvc 对于异常处理这块提供了支持,通过 SpringMvc 提供的全局异常处理机制,能够将所有类型的异常处理从各处理过程解耦出来,这样既保证了
相关处理过程的功能较单一,也实现了异常信息的统一处理和维护。全局异常实现方式
Spring MVC 处理异常有 3 种方式
1.使用 Spring MVC 提供的简单异常处理器 SimpleMappingExceptionResolver;
2.实现 Spring 的异常处理接口 HandlerExceptionResolver 自定义自己的异常处理器;
3.使用@ExceptionHandler 注解实现异常处理;
1)使用xml的配置来实现异常处理
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="defaultErrorView" value="error"></property> <property name="exceptionAttribute" value="ex"></property> <property name="exceptionMappings"> <props> <prop key="com.shsxt.exception.ParamException">params</prop> </props> </property> </bean>
2)实现接口来处理异常
import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Component public class myException implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { ModelAndView modelAndView=new ModelAndView(); modelAndView.addObject("ex",ex.getMessage()); modelAndView.setViewName("error"); if(ex instanceof ParamException){ ParamException pe=(ParamException)ex; modelAndView.addObject("ex",pe.getMessage()); modelAndView.setViewName("params"); } return modelAndView; } }
三,注解来实现异常处理
import com.shsxt.exception.ParamException; import org.springframework.web.bind.annotation.ExceptionHandler; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class BaseController { @ExceptionHandler public String exec(HttpServletRequest request, HttpServletResponse response,Exception ex){ request.setAttribute("ex",ex.getMessage()); if(ex instanceof ParamException){ ParamException pe=(ParamException)ex; request.setAttribute("ex",pe.getMessage()); return "params"; } return "error"; } }