一、SpringMVC使用—注解使用
放行JSP访问
JSP是服务器资源
修改SpringMVC前端控制器拦截所有请求方式为“/”
SpringMVC随着版本的迭代提供了越来越完善的注解
1.1 配置mvc采用注解驱动
-
spring-context.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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config/> <context:component-scan base-package="com.qfedu"/> </beans>
-
spring-servlet.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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <mvc:annotation-driven/> <!--配置处理器映射器--> <!--配置视图解析器--> </beans>
1.2 创建控制器
1.2.1 创建控制器
/**
* 使用注解创建控制器
* 1.添加@Controller注解,无需继承或实现任何类
* 2.在一个控制器中可以创建多个方法,用于处理不同的请求
* 3.添加@RequestMapping注解声明请求此控制器方法的前缀(可选)
*/
@Controller
@RequestMapping("/test")
public class TestController{
}
1.2.2 创建处理方法
/**
* 控制器中处理请求的方法必须遵守以下原则
* 1.方法名可以自定义
* 2.返回类型可以是ModelAndView、String、void
* ModelAndView
* String
* void
* 3.参数:可以根据需要自定义
* 4.需要通过@RequestMapping注解来指定此方法的访问路径
*/
@RequestMapping("/aaa")
public ModelAndView method1() {
System.out.println("----test aaa");
ModelAndView modelAndView = new ModelAndView("/a.jsp");
modelAndView.addObject("tips","hello page a");
return modelAndView;
}
@RequestMapping("/bbb")
public String method2() {
System.out.println("----test bbb");
return "/b.jsp";
}
@RequestMapping("/ccc")
public void method3(HttpServletResponse response) throws IOException {
//用于处理ajax请求
System.out.println("----test ccc");
PrintWriter out = response.getWriter();
out.println("jsonstr");
out.flush();
out.close();
}
1.2.3 @Controller注解和@RequestMapping
@Controller
-
类注解,用于声明SpringMVC的控制器
-
@Controller 区别于@Service、@Repository、@Component
@RequestMapping
-
类注解(控制器类,用于声明处理方法请求路径的前缀)、方法注解(用于声明处理请求方法的请求URL)
-
value属性,用于指定请求的url
-
method属性,用于限定客户端的请求方式
@RequestMapping(value = "/aaa",method = RequestMethod.GET ) /**http请求方式(主要的四种): * RequestMethod.GET * RequestMethod.POST * RequestMethod.PUT * RequestMethod.DELETE */ public ModelAndView method1() { System.out.println("----test method1"); ModelAndView modelAndView = new ModelAndView("/a.jsp"); modelAndView.addObject("tips","hello page a"); return modelAndView; }
1.3 传值(接收请求参数)
1.3.1 实例 添加图书信息
-
前端
<form action="book/add" method="post"> <p>图书名称:<input type="text" name="name"/></p> <p>图书作者:<input type="text" name="author"/></p> <p>图书价格:<input type="text" name="price"/></p> <p>出版日期:<input type="text" name="time"/></p> <input type="submit" value="提交"> </form>
-
控制器
@Controller @RequestMapping("/book") public class BookController { @RequestMapping(value = "/add",method = RequestMethod.POST) public ModelAndView addBook(){ return null; } }
1.3.2 通过定义基本类型参数接收提交的数据
在控制器的处理方法中,定义参数接收提交的数据
-
如果参数的名字与提交数据的key一一对应,则可以直接接收数据
@RequestMapping(value = "/add",method = RequestMethod.POST) public ModelAndView addBook(String name, String author, double price, Date time){ System.out.println("-----------book add"); System.out.println("name:"+name); System.out.println("author:"+author); System.out.println("price:"+price); System.out.println("time:"+time); return null; }
-
如果处理请求方法的参数名与提交数据的key不一致,需要通过
@RequestParam
进行适配@RequestMapping(value = "/add",method = RequestMethod.POST) public ModelAndView addBook(@RequestParam("name") String bookName, @RequestParam("author") String bookAuthor, @RequestParam("price") double bookPrice, @RequestParam("time") Date bookTime){ System.out.println("-----------book add"); System.out.println("name:"+bookName); System.out.println("author:"+bookAuthor); System.out.println("price:"+bookPrice); System.out.println("time:"+bookTime); return null; }
1.3.3 通过对象接收提交的数据
-
创建实体类(需要提供set方法)
public class Book { private int bookId; private String bookName; private String bookAuthor; private double bookPrice; private Date bookTime; //无参构造器 //有参构造器 //get、set方法 //toString }
-
在控制器处理方法中通过对象接收提交的数据(前端提交数据的key要与实体类的属性名一致)
@RequestMapping(value = "/add",method = RequestMethod.POST) public ModelAndView addBook(Book book){ System.out.println("-----------book add"); System.out.println(book); return null; }
1.3.4 @PathVariable
SpringMVC提供了良好的RESTful的URL设计风格的支持
RESTful:一个URL(请求路径)对应服务器唯一的资源
//传统的URL风格:
// http://localhost:8080/springmvc_demo2/book/delete?bookId=1
// http://localhost:8080/springmvc_demo2/book/delete?bookId=2
//RESTful风格:
//http://localhost:8080/springmvc_demo2/book/delete/1/1
//http://localhost:8080/springmvc_demo2/book/delete/2/3
@PathVariable
获取url中的动态参数
@RequestMapping("/delete/{tid}/{bid}")
public String deleteBook(@PathVariable("tid") int typeId,
@PathVariable("bid") int bookId){
System.out.println("----------book delete");
System.out.println(typeId);
System.out.println(bookId);
return null;
}
1.3.5 @CookieValue
@CookieValue用于获取cookie中的值
-
前端JSP页面
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %> <html> <head> <title>Title</title> </head> <script type="text/javascript"> function writeCookie(){ document.cookie = "aaa=wahaha"; } </script> <body> <input type="button" value="写Cookie" οnclick="writeCookie()"/> <a href="book/test">GO</a> </body> </html>
-
控制器接收cookie中的值
@RequestMapping("/test") public String getCookieValue(@CookieValue("JSESSIONID") String sessionId, @CookieValue("aaa") String str){ System.out.println("-----------getCookieValue"); System.out.println(sessionId); System.out.println(str); return null; }
1.3.6 @RequestHeader
HTTP请求可以将参数通过请求头传递,我们可以通过@RequestHeader在控制器中获取请求头传递的数据
@RequestMapping("/test2")
public String getHeaderValue(@RequestHeader("User-Agent") String userAgent){
System.out.println("-------getHeaderValue");
System.out.println(userAgent);
return null;
}
1.4 在控制器中使用ServletAPI
ServletAPI指的是Javaweb的对象:request\session\response
- 在控制器的处理方法中直接定义需要使用的web对象即可
@RequestMapping("/login")
public String login(String username, String password, HttpSession session){
System.out.println("--------------user login");
session.setAttribute("name",username);
return "/b.jsp";
}
1.5 转发和重定向
当控制器接收请求参数并完成处理之后,需要对用户的请求的进行响应;
- 如果客户端发送的是同步请求,我们需要在控制器中进行转化和重定向
- 如果客户端发送的是异步请求,我们需要响应JSON数据
控制器中处理请求的方法返回类型可以是ModelAndView、String、void
-
通过ModelAndView实现转发和重定向
-
转发
ModelAndView modelAndView = new ModelAndView("/index.jsp"); return modelAndView;
-
重定向
ModelAndView modelAndView = new ModelAndView("redirect:/index.jsp"); return modelAndView;
-
-
通过返回string实现转发和重定向
-
转发
@RequestMapping("/delete/{tid}/{bid}") public String deleteBook(@PathVariable("tid") int typeId, @PathVariable("bid") int bookId){ return "/index.jsp"; }
-
重定向
@RequestMapping("/delete/{tid}/{bid}") public String deleteBook(@PathVariable("tid") int typeId, @PathVariable("bid") int bookId){ return "redirect:/index.jsp"; }
-
1.6 从控制器传值到转发的页面
1.6.1 使用ModelAndView
-
控制器中处理请求的方法 返回 ModelAndView对象
@RequestMapping(value = "/add",method = RequestMethod.POST) public ModelAndView addBook(Book book){ System.out.println("-----------book add"); System.out.println(book); ModelAndView modelAndView = new ModelAndView("/index.jsp"); modelAndView.addObject("book",book); //modelAndView当作request对象使用 return modelAndView; }
1.6.2 使用request对象
-
当控制器中处理请求的方法返回的string类型,则可以通过HttpServletRequest对象传值
@RequestMapping("/delete/{tid}/{bid}") public String deleteBook(@PathVariable("tid") int typeId, @PathVariable("bid") int bookId, HttpServletRequest request){ System.out.println("----------book delete"); request.setAttribute("tips","这是通过request传递的数据"); return "/b.jsp"; }
1.6.3 使用Model对象
- 当控制器中处理请求的方法返回的string类型,也可以通过Model对象传值
@RequestMapping("/delete/{tid}/{bid}")
public String deleteBook(@PathVariable("tid") int typeId,
@PathVariable("bid") int bookId,
Model model){
System.out.println("----------book delete");
model.addAttribute("tips","这是通过model传递的数据");
return "/b.jsp";
}
1.7 解决中文乱码问题
1.7.1 前端编码
-
JSP需要设置 pageEncoding=“UTF-8”
-
HTML需要设置 charset=“UTF-8”
1.7.2 服务器编码
-
修改tomcat/conf/server.xml
<Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8"/>
1.7.3 在SpringMVC的web应用中设置编码过滤器
-
在web.xml中配置SpringMVC提供的编码过滤器
<filter> <filter-name>characterEncoding</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> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
1.8 自定义日期格式转换
-
创建自定义日期转换类
public class MyDateConverter implements Converter<String, Date> { private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); public Date convert(String s) { Date date = null; try { date = format.parse(s); } catch (ParseException e) { e.printStackTrace(); } return date; } }
-
在spring-servlet.xml中配置自定义日期转换类
<mvc:annotation-driven conversion-service="converters"/> <bean id="converters" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.qfedu.utils.MyDateConverter"></bean> </set> </property> </bean>
二、控制器响应AJAX请求
2.1 使用response对象输出流响应ajax请求
-
控制器处理请求的方法返回类型为void
@RequestMapping("/check") public void check(String username, HttpServletResponse response) throws IOException { System.out.println("-----------user check"); System.out.println(username); ResultVO vo = null; if(username.startsWith("admin")){ vo = new ResultVO(1,"fail"); }else{ vo = new ResultVO(0,"success"); } String jsonstr = new Gson().toJson(vo); response.setContentType("application/json"); response.setCharacterEncoding("utf-8"); PrintWriter out = response.getWriter(); out.println(jsonstr); out.flush(); out.close(); }
2.2 使用@ResponseBody注解响应ajax请求
-
添加jackson依赖
- jackson-core
- jackson-databind
- jackson-annotations
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency>
-
控制器中处理ajax请求的方法直接返回需要转换成json格式的对象,并且添加
@ResponseBody
@ResponseBody @RequestMapping("/check") public ResultVO check(String username) { System.out.println("-----------user check"); System.out.println(username); ResultVO vo = null; if(username.startsWith("admin")){ vo = new ResultVO(1,"fail"); }else{ vo = new ResultVO(0,"success"); } return vo; }
三、文件上传和下载
3.1 客户端提交文件
- 数据提交方式为post
- 数据不进行压缩编码传输 enctype=“multipart/form-data”
<form action="" method="post" enctype="multipart/form-data">
<fieldset style="width: 400px; height: 300px">
<legend>添加图书信息</legend>
<div style="padding: 15px">
<p>图书名称:<input type="text" name=""/></p>
<p>图书封面:<input type="file" name=""/></p>
<p>图书作者:<input type="text" name=""/></p>
<p>图书价格:<input type="text" name=""/></p>
<p><input type="submit" value="提交"/></p>
</div>
</fieldset>
</form>
3.2 控制器接收文件
3.2.1 添加依赖
<!--SpringMVC文件上传-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
3.2.2 配置文件解析器
<!--配置文件数据解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="5242880"/>
<property name="maxInMemorySize" value="1000000"/>
<property name="defaultEncoding" value="utf-8"/>
</bean>
3.2.3 控制器
@RequestMapping("/add")
public String add(MultipartFile bookImg, HttpServletRequest request) throws IOException {
//获取文件的原始名称
String originalFilename = bookImg.getOriginalFilename();
//截取后缀名
String ext = originalFilename.substring(originalFilename.lastIndexOf("."));
//生成新得文件名
String fileName = UUID.randomUUID().toString().replace("-","")+ext;
//获取项目中files目录在服务器中的路径
String dir = request.getServletContext().getRealPath("files");
//dir+"/"+fileName
bookImg.transferTo(new File(dir+"/"+fileName));
return "/tips.jsp";
}
四、统一异常处理
当服务器出现异常时,为了能够给用户提供友好的提示,SpringMVC提供了统一异常处理
4.1 HTTP异常状态统一处理
在web.xml配置“error-page”
<!--统一http错误状态提示-->
<error-page>
<error-code>404</error-code>
<location>/404.jsp</location>
</error-page>
4.2 SpringMVC提供的统一异常处理
- 创建异常处理类
@ControllerAdvice
public class MyExceptionHandler {
//@ExceptionHandler 将此方法定义为一个异常处理的方法
// 可以处理某个具体的异常,也可以统一处理所有异常
@ExceptionHandler(Exception.class)
public String handleEx1(Exception e){
System.out.println("--------------------ex");
e.printStackTrace();
return "/error.jsp";
}
}
五、拦截器
5.1 拦截器介绍
SpringMVC提供的拦截器类似于Servlet开发中用到的过滤器,用于对处理器进行预处理和后处理,用户可以通过自定义拦截器来实现一些特定的功能。
拦截器链:将多个连接器按照一定的顺序构成一个链条
拦截器和过滤器
- 过滤器
- 过滤器是servlet规范的一部分,任何Java web工程都可以使用
- 过滤器是在web.xml中配置,可以拦截所有请求
- 拦截器
- 拦截器属于SpringMVC框架本身,只有在SpringMVC工程中才能使用
- 拦截器只会拦截对指定的控制器的请求,不会拦截对JSP\HTML\CSS\JS等资源的请求
5.2 自定义拦截器
-
创建拦截器
public class MyInterceptor01 implements HandlerInterceptor{ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("----------------preHandle"); //前置处理方法返回值 //返回true 表示执行拦截器之后允许继续执行 //返回false 表示不放行 return true; } public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("----------------postHandle"); } }
-
配置拦截器 (spring-servlet.xml)
<!--配置自定义拦截器--> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/book/**"/> <mvc:exclude-mapping path="/book/add"/> <bean class="com.qfedu.handlers.MyInterceptor01"></bean> </mvc:interceptor> </mvc:interceptors>