json数据交互
案例实现
- 导入pom依赖
说明:springmvc框架,默认使用HttpMessageConverter消息转换器,进行json格式数据转换。需要加入jackson依赖包支持
<!--依赖管理-->
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<!--Apache的文件解析器-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
- SpringMVC核心配置文件
<?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"
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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- bean definitions here -->
<!--开启包扫描注解-->
<context:component-scan base-package="cn.itcast.controller"></context:component-scan>
<!--springmvc的注解驱动-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--视图解析器的前缀和后缀-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="suffix" value=".jsp"></property>
<property name="prefix" value="/WEB-INF/jsp/"></property>
</bean>
<!--前端控制器是/,所以要释放静态资源-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
</beans>
- web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!--配置前端控制器-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--将springmvc的配置文件交给前端控制器-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:SpringConfig.xml</param-value>
</init-param>
</servlet>
<!--拦截规则-->
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--乱码过滤器-->
<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>
</web-app>
- log4j日志文件
### direct log messages to stdout ###
### 输出源的配置 语法 log4j.appender.输出源的名字=输出源的实现类 ###
### log4j.appender.输出源的名字.属性=属性值 ###
log4j.appender.a=org.apache.log4j.ConsoleAppender
log4j.appender.a.Target=System.out
log4j.appender.a.layout=org.apache.log4j.PatternLayout
log4j.appender.a.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n
### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=/home/travel.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n
### set log levels - for more verbose logging change 'info' to 'debug' ###
### 日志记录器的配置,固定语法 log4j.rootLogger=输出级别, 输出源,输出源... ###
log4j.rootLogger=debug, a,file
- MyController
@Controller
public class MyController {
@RequestMapping("/demo")
public String demo() {
return "demo";
}
@ResponseBody //直接声明一个方法,返回值类型是java实体对象类型.在方法上添加@ResponseBody注解通过springmvc转换json
@RequestMapping("/returnJson")
public Item returnJson() {
Item item = new Item();
item.setName("耳机");
item.setPrice(1000);
item.setDetail("详情");
return item;
}
@RequestMapping("/getJson")
@ResponseStatus(HttpStatus.OK)//void类型,并且没有响应体
public void getJson(@RequestBody Item item) { //@RequestBody 让springmvc将请求中的json转换成java中的对象
System.out.println(item);
}
}
如果一个controller中所有的方法全部都是json返回值,我们直接使用@RestController来替代之前的@Controller
restful支持
restful介绍
- restful是一种软件设计风格
- restful根据HTTP请求方法:
POST/GET/PUT/DELETE,定义了资源的操作方法:新增/查询/修改/删除 - restful风格的优点:
结构清晰、符合标准、易于理解、 扩展方便、请求的url更加简洁,得到越来越多网站的采用
案例实现
步骤:
/**
* restful风格:
* 需求:
* /item/1 get 查询id为1的商品信息
* /item/1 delete 删除id为1的商品
* /item/1 put 更新id为1的商品
* /item post 新增
*
* 步骤:
* 1.后台需要4个方法来处理请求.但是这4个方法映射的路径是一样,只是限定请求的方式不一样
* 2.前端发送请求,请求的地址一样,但是请求的方式不一样:
* a.通过rest插件发送put和delete请求
* b.springmvc提供了一个HiddenHttpMethodFilter,将所有的POST请求转换成对应的post或者delete或者get或者put请求
* 根据POST请求中的_method参数的值进行转换
*/
RestfulController
@Controller
public class RestfulController {
@RequestMapping(value = "/item/{id}", method = RequestMethod.GET)
@ResponseStatus(HttpStatus.OK)
public void queryItemById(@PathVariable("id") String id) {
System.out.println("查询商品:" + id);
}
@RequestMapping(value = "/item/{id}", method = RequestMethod.DELETE)
@ResponseStatus(HttpStatus.OK)
public void deleteItemById(@PathVariable String id) {
System.out.println("删除商品:" + id);
}
@RequestMapping(value = "/item/{id}", method = RequestMethod.PUT)
@ResponseStatus(HttpStatus.OK)
public void updateItemById(@PathVariable String id) {
System.out.println("修改商品:" + id);
}
@RequestMapping(value = "/item/{id}", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.OK)
public void add() {
System.out.println("添加商品");
}
}
前端页面请求:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/item/1" method="post">
<input type="hidden" name="_method" value="GET">
<input type="submit" value="get请求">
</form>
<form action="/item/2" method="post">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="delete请求">
</form>
<form action="/item/3" method="post">
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="put请求">
</form>
<form action="/item/1" method="post">
<input type="hidden" name="_method" value="POST">
<input type="submit" value="post请求">
</form>
</body>
</html>
web.xml
请求方式过滤器
<!--请求方式过滤器-->
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
@PathVariable注解
请求中,路径中的变量
路径中的变量:
* 变量格式 : {变量名}
*
* 获取路径中的变量格式 @PathVariable(变量名)
* 如果变量名和方法名一样, 直接写@PathVariable
文件上传
servlet中的文件上传
-
前端 a.请求的方式必须是post类型. b.inpute type=file 文件标签 c.enctype=multipart/form-data
-
后台servlet a.在servlet上添加一个注解,用来解析文件上传的这种数据格式类型 b.直接使用request.getPart();获取文件
文件上传三要素
- 表单的提交方式 method=“POST”
- 表单的enctype属性是多部分表单形式 enctype=“multipart/form-data"
- 表单项(元素)type=“file”
<form action="" method="post" enctype="multipart/form-data">
姓名:<input type="text" name="username"> <br>
头像:<input type="file" name="picFile"> <br>
</form>
SpringMVC实现文件上传
案例实现
步骤:
/**
* springmvc的文件上传:
* 前端:
* a.请求的方式必须是post类型.
b.inpute type=file 文件标签
c.enctype=multipart/form-data
*
* 后台:
* springmvc是通过apache的fileUpload依赖来解析文件的.
* 1.需要引入apache的fileupload依赖
* 2.配置一个文件解析器
* 3.直接在handler中声明MultipartFile 类型的变量,然后直接操作
*/
pom依赖
<!--apache的文件解析器-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
springMVC.xml
<!--配置文件解析器-->
<!--id:必须是multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--限制文件上传的大小 字节-->
<property name="maxUploadSize" value="10240000"></property>
<!--上传的文件名的编码-->
<property name="defaultEncoding" value="utf-8"></property>
</bean>
UploadFileController
@Controller
public class UploadFileController {
@ResponseStatus(HttpStatus.OK)
@RequestMapping("/updateItem.do")
public void updateItem(Item item, @RequestParam("img") MultipartFile pictureFile) {
System.out.println("表单参数插入到数据库:" + item);
//获取源文件名
String originalFilename = pictureFile.getOriginalFilename();
//保存图片
try {
pictureFile.transferTo(new File("d://" + originalFilename));
} catch (IOException e) {
e.printStackTrace();
}
}
}
统一异常处理
概述
-
请求流程:
客户端(浏览器)–>前端控制器(DispatcherServlet)–>表现层(controller)–>业务层(service)–>持久层(dao) -
处理思路:
从持久层dao开始,每一层发生异常都向上一层抛出,一直抛到前端控制器(DispatcherServlet)。到此不能再抛出,我们不能把异常抛给用户
在前端控制器需要进行异常处理,前端控制器是中央处理器,不负责具体的业务处理,因此在前端控制器需要调用异常处理器进行异常处理,最终返回一个友好的异常提示页面,提示用户
案例实现
需求:根据商品id查询商品,如果查询不到商品,抛出商品不存在异常
步骤:
- 1.自定义异常
- 2.抛出运行时异常
- 3.自定义异常处理器,实现HandlerExceptionResolver接口
- 4.在springmvc中配置当前异常处理器对象
NoResultException
//自定义一个异常类
public class NoResultException extends Exception {
public NoResultException(String message) {
super(message);
}
}
Controller
@Controller
public class ExceptionController {
@ResponseStatus(HttpStatus.OK)
@RequestMapping("/findItemById")
public void findItemById(Integer id) throws NoResultException {
if (id > 5) {
System.out.println("查询id为" + id + "的商品不存在");
//throw new NoResultException("查询id为" + id + "的商品不存在");
} else {
System.out.println("查询id为" + id + "的商品信息");
}
}
}
MyExceptionResolver
//自定义异常处理器,捕获到的所有异常,都在这里统一处理
public class MyExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
ModelAndView modelAndView = new ModelAndView();
//需要判断异常的类型
if (ex instanceof NoResultException) {
//获取业务中的错误信息
String message = ex.getMessage();
//保存数据
modelAndView.addObject("errorMsg", message);
} else if (ex instanceof MaxUploadSizeExceededException) {
modelAndView.addObject("errorMsg", "上传的图片过大");
}
//错误的页面视图
modelAndView.setViewName("error");
return modelAndView;
}
}
SpringMVC.xml
<!--配置异常处理器-->
<bean id="exceptionResolver" class="cn.itcast.exceptionHandler.MyExceptionResolver"></bean>
SpringMVC拦截器
概述
- springmvc框架中的拦截器,相当于web阶段学习的过滤器(filter),可以实现前置增强和后置增强功能
- 在springmvc框架中,拦截器可以对处理器方法执行预处理(前置增强),和执行后处理(后置增强)
-
web开发中过滤器的作用: 在请求访问目标资源之前进行拦截,一般都是通用性功能的抽取。(多个请求共有功能的抽取) 例如乱码的处理,用于登录的判断,权限的判断。。。。
-
在springmvc中,只有一个servlet。所有的请求,都是经过servlet再派发到controller。 ItemController进行拦截。 /item/save /item/delete
快速入门
需求:
- 创建一个demo级别的handler
- 创建一个类,实现拦截器接口 HandlerInterceptor
- 在springmvc.xml中配置拦截器
Controller
@Controller
@RequestMapping("/interceptor")
public class InterceptorController {
@RequestMapping("/demo")
public String demo(Model model) {
model.addAttribute("msg", "controller");
System.out.println("经过了controller");
return "demo";
}
}
interceptor
//拦截器
public class MyInterceptor1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("在controller的handler之前执行");
return true; //返回true,表示放行.
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("在controller的handler之后执行,但是在视图渲染之前");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
System.out.println("在视图渲染之后做这个功能");
}
}
/**输出结果为:
* 在controller的handler之前执行
* 经过了controller
* 在controller的handler之后执行,但是在视图渲染之前
* 2020-06-23 21:04:01,587 [http-nio-8080-exec-1] [org.springframework.web.servlet.DispatcherServlet]-[DEBUG] Rendering view [org.springframework.web.servlet.view.InternalResourceView: name 'demo'; URL [/WEB-INF/jsp/demo.jsp]] in DispatcherServlet with name 'DispatcherServlet'
* 2020-06-23 21:04:01,587 [http-nio-8080-exec-1] [org.springframework.web.servlet.view.InternalResourceView]-[DEBUG] Added model object 'msg' of type [java.lang.String] to request in view with name 'demo'
* 2020-06-23 21:04:01,588 [http-nio-8080-exec-1] [org.springframework.web.servlet.view.InternalResourceView]-[DEBUG] Forwarding to resource [/WEB-INF/jsp/demo.jsp] in InternalResourceView 'demo'
* 在视图渲染之后做这个功能
*
*
*
*/
SpringMVC.xml
<!--
配置拦截器
声明拦截器配置
-->
<mvc:interceptors>
<!-- 配置单个拦截器-->
<mvc:interceptor>
<!-- 配置拦截器拦截的路径-->
<mvc:mapping path="/interceptor/*"/>
<!-- 配置拦截器对象-->
<bean class="cn.itcast.interceptors.MyInterceptor1"></bean>
</mvc:interceptor>
</mvc:interceptors>
拦截器作用方法说明
拦截器链
<!--
配置拦截器
声明拦截器配置
拦截器链:多个拦截器组成的整体. 按照上下的配置顺序
-->
<mvc:interceptors>
<!-- 配置单个拦截器-->
<mvc:interceptor>
<!-- 配置拦截器拦截的路径-->
<mvc:mapping path="/interceptor/*"/>
<!-- 配置拦截器对象-->
<bean class="cn.itcast.interceptors.MyInterceptor1"></bean>
</mvc:interceptor>
<!-- 配置单个拦截器-->
<mvc:interceptor>
<!-- 配置拦截器拦截的路径-->
<mvc:mapping path="/interceptor/*"/>
<!-- 配置拦截器对象-->
<bean class="cn.itcast.interceptors.MyInterceptor2"></bean>
</mvc:interceptor>
<!-- 配置单个拦截器-->
<mvc:interceptor>
<!-- 配置拦截器拦截的路径-->
<mvc:mapping path="/interceptor/*"/>
<!-- 配置拦截器对象-->
<bean class="cn.itcast.interceptors.MyInterceptor3"></bean>
</mvc:interceptor>
</mvc:interceptors>
拦截器应用实现
案例需求
-
用户访问商品列表数据,判断用户是否登录: 1.如果用户已经登录,直接访问商品列表数据 2.如果用户未登录,先到登录页面执行登录。成功登录以后再访问商品列表数据
代码实现
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!--配置前端控制器-->
<servlet>
<servlet-name>DispatcherServlet</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>
<!--配置拦截规则-->
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
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:context="http://www.springframework.org/schema/context"
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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--开启注解扫描-->
<context:component-scan base-package="cn.itcast"></context:component-scan>
<!--springmvc的注解驱动-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--拦截路径是/,所以开启加载静态资源-->
<mvc:default-servlet-handler></mvc:default-servlet-handler>
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前缀和后缀-->
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/item/*"/>
<bean class="cn.itcast.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
</beans>
UserController
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/goToLogin")
public String goToLogin() {
return "login";
}
@RequestMapping("/login")
public String login(HttpSession session) {
//表示登录成功
session.setAttribute("user","user");
return "list";
}
}
ItemController
@Controller
@RequestMapping("/item")
public class ItemController {
@RequestMapping("/goToItemList")
public String goToItemList() {
//商品信息页面
return "list";
}
}
LoginInterceptor
//登录拦截器
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//判断登录权限
Object user = request.getSession().getAttribute("user");
//判断
if (user != null) {
//登录成功
return true;
} else {
//登录失败
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}