1.SpringMVC介绍
SpringMVC是Spring框架中的一个组件,是一个轻量级的web的MVC框架,充当controller,其本质就是一个Servlet。
1.1 传统Servlet的不足
每个请求,都需要定义一个Servlet。虽然可以在service方法中,根据业务标识进行业务分发,但是每个Servlet中的service方法的实现是重复。如果想要对service进行更高层次的封装,就可以解决service的重复代码问题。
每个请求的参数,都需要根据request对象,从Map逐一的获取,单调且含量低。将所有的参数,自动封装映射,简化开发。
request.getParameter(“”)
每个Servlet,向客户端返回数据时,需要单独的处理。
request.getRequestDispatcher(“/路径”).forward(request,response)
Response.sendRedirect(“/路径”)
针对于Servlet在实际使用中的不便,Spring中提供了组件,SpringMVC,更进一步的简化了Servlet的开发。
1.2 SpringMVC的架构
1.2.1 DispatcherServlet
核心控制器,本质上就是一个Servlet,处理所有的客户端的请求。根据请求的资源路径,在处理器映射器中查找对应的处理器。
1.2.2 HandlerMapping
处理器映射器,存储所有当前程序中的处理器,如果在处理器映射器中查找不到资源路径,直接返回404。
1.2.3 HandlerAdapter
处理器适配器,用于适配各种处理器,调用具体的处理器程序。
1.2.4 Handler
具体处理器,开发者实现相应接口或者使用注解声明的程序。用于处理具体的请求。
1.2.5 ViewResolver
视图解析器,根据处理器返回的数据,进行数据处理,将数据处理成相应的格式。
JSP/JSON等等。
2.SpringMVC使用
2.1 SpringMVC入门使用
2.1.1 导入SpringMVC相关jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>01-mvc01</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- 引入springmvc 相关jar包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
</dependencies>
</project>
2.1.2 编写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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 配置了一个自定义的处理器 -->
<bean id="controller01" name="/controller01.do" class="com.bjpowernode.controller.Controller01"></bean>
<bean id="controller02" name="/controller02.do" class="com.bjpowernode.controller.Controller02"></bean>
<!-- 开启springmvc 注解 -->
<!-- 开启组件扫描 -->
<context:component-scan base-package="com.*" />
<!-- 开启springmvc 相关注解 -->
<mvc:annotation-driven />
</beans>
2.1.3 编写相关类
package com.bjpowernode.controller;
import org.springframework.web.HttpRequestHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class Controller01 implements HttpRequestHandler {
@Override
public void handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
System.out.println("你好啊 springmvc");
}
}
package com.bjpowernode.controller;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Controller02 implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
System.out.println("Hello SpringMVC 02");
//模型视图
//模型就是数据
//视图 界面
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name","Hello SpringMVC");
modelAndView.setViewName("/index.html");//springmvc中 /表示当前项目
return modelAndView;
}
}
package com.bjpowernode.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping
public class Controller03 {
@RequestMapping("hello1.do")
public String hello(String name){
System.out.println("name:"+name);
System.out.println("你好springmvc");
return "/index.html";
}
@RequestMapping("hello2.do")
public String hello1(String name){
System.out.println("name:"+name);
System.out.println("你好springmvc");
return "/index.html";
}
}
2.1.4 在web.xml中配置SpringMVC
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<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>
<!-- 配置服务器启动时 就初始化DispatcherServlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
2.1.5 进行测试
使用bean标签的name属性进行访问。注意,每个名字必须有个/,如果多个名字,之间使用逗号。
2.2 SpringMVC的数据绑定
在SpringMVC中为了简化开发,SpringMVC对请求的参数进行预处理,SpringMVC支持按照参数名称,直接将请求参数封装传递给处理器中的方法,处理无需单独的获取。
2.2.1 请求参数
请求参数,是指基本数据类型和字符串、对象、数组、Map等。
2.2.2 获取请求参数
package com.bjpowernode.controller;
import com.bjpowernode.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@Controller
@RequestMapping("/param")
public class ParamController {
/**
* 处理简单的参数
* @return
*/
@RequestMapping("/simple.do")
public String doSimpleParam(Integer id,boolean flag,String name,@RequestParam("City") String city){
System.out.println("id: "+id);
System.out.println("flag: "+flag);
System.out.println("name: "+name);
System.out.println("city: "+city);
return "/success.html";//默认当做内部转发处理 默认当做视图路径
}
/**
* 使用对象接收请求参数
* 请求参数的名称 必须 和 对象中属性名一致 类型要支持转换
* @param user
* @return
*/
@RequestMapping("/obj.do")
public String objParam(User user){
System.out.println("id: "+user.getId());
System.out.println("flag: "+user.getFlag());
System.out.println("name: "+user.getName());
return "/success.html";//默认当做内部转发处理 默认当做视图路径
}
/**
* 使用map接收请求参数
* 默认是不支持使用map集合接收数据 需要使用注解@RequestParam
* RequestParam :
* name/value : 绑定请求参数 ,默认根据名称注入值,当名称不一致,可以使用RequestParam设置对应的参数的名称,进行绑定
* required : 是否需要这个参数 默认true 如果有使用了RequestParam这个注解,默认必须传这个参数 如果不是必传 设置为 false
* defaultValue : 如果没有这个请求参数时或者请求参数值为null 设置默认值
* @param param
* @return
*/
@RequestMapping("/map.do")
public String mapParam(@RequestParam Map<String,Object> param){
System.out.println("id: "+param.get("id"));
System.out.println("flag: "+param.get("flag"));
System.out.println("name: "+param.get("name"));
return "/success.html";//默认当做内部转发处理 默认当做视图路径
}
@RequestMapping("/arr.do")
public String arr(Integer id,boolean flag,String name,String[] likes){
System.out.println("id: "+id);
System.out.println("flag: "+flag);
System.out.println("name: "+name);
List<String> strings = Arrays.asList(likes);
System.out.println(strings);
return "/success.html";//默认当做内部转发处理 默认当做视图路径
}
@RequestMapping("/list.do")
public String arr(Integer id,boolean flag,String name,@RequestParam("likes") List<String> likes){
System.out.println("id: "+id);
System.out.println("flag: "+flag);
System.out.println("name: "+name);
System.out.println(likes);
return "/success.html";//默认当做内部转发处理 默认当做视图路径
}
}
2.2.3 页面代码
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>简单的数据</h1>
<form action="param/simple.do" method="get">
<p>ID:<input name="id" /></p>
<p>boolean:<input name="flag" type="radio" value="true" />男<input name="flag" type="radio" value="false" />女</p>
<p>String:<input name="name" /></p>
<p>city:<input name="City" /></p>
<input type="submit" value="提交" />
</form>
<h1>对象的数据</h1>
<form action="param/obj.do" method="get">
<p>ID:<input name="id" /></p>
<p>boolean:<input name="flag" type="radio" value="true" />男<input name="flag" type="radio" value="false" />女</p>
<p>String:<input name="name" /></p>
<input type="submit" value="提交" />
</form>
<h1>map的数据</h1>
<form action="param/map.do" method="get">
<p>ID:<input name="id" /></p>
<p>boolean:<input name="flag" type="radio" value="true" />男<input name="flag" type="radio" value="false" />女</p>
<p>String:<input name="name" /></p>
<input type="submit" value="提交" />
</form>
<h1>数组的数据</h1>
<form action="param/arr.do" method="get">
<p>ID:<input name="id" /></p>
<p>boolean:<input name="flag" type="radio" value="true" />男<input name="flag" type="radio" value="false" />女</p>
<p>String:<input name="name" /></p>
<p>likes:<input name="likes" type="checkbox" value="篮球" />篮球<input name="likes" type="checkbox" value="足球" />足球</p>
<input type="submit" value="提交" />
</form>
<h1>list的数据</h1>
<form action="param/list.do" method="get">
<p>ID:<input name="id" /></p>
<p>boolean:<input name="flag" type="radio" value="true" />男<input name="flag" type="radio" value="false" />女</p>
<p>String:<input name="name" /></p>
<p>likes:<input name="likes" type="checkbox" value="篮球" />篮球<input name="likes" type="checkbox" value="足球" />足球</p>
<input type="submit" value="提交" />
</form>
</body>
</html>
2.3 SpringMVC的跳转
在SpringMVC中,默认的跳转方式内部转发,,每个URL前面默认有forward:
,默认会将方法的返回值当做视图的路径处理。并且,在SpringMVC中,/表示当前项目根目录。如果想要使用重定向,则使用关键字:redirect:/路径。
2.3.1 代码示例
package com.bjpowernode.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("jump")
public class JumpController {
@RequestMapping("forward.do")
public String forward(){
System.out.println("内部转发跳转!");
return "forward:/success.html";
}
@RequestMapping("forward1.do")
public String forward1(){
System.out.println("内部转发跳转!");
return "/success.html";
}
@RequestMapping("redirect.do")
public String redirect(){
System.out.println("重定向跳转!");
return "redirect:/success.html";
}
}
2.4 SpringMVC支持内置的对象
在SpringMVC中,支持为处理器中的方法注入内置的对象,如:HttpServletRequest、HttpServletResponse、HttpSession、Model等。
/**
*
* @param request
* @param resp
* @param session
* @param model 是springmvc中 推荐使用参数传递的容器 当参数发生覆盖 优先使用model中的参数
* @throws IOException
*/
@RequestMapping("servletParam.do")
public void servletParam(HttpServletRequest request, HttpServletResponse resp, HttpSession session, Model model) throws IOException {
String name = request.getParameter("name");
System.out.println(name);
System.out.println(request);
System.out.println(resp);
System.out.println(session);
System.out.println(model);
resp.sendRedirect("success.html");
//return "/success.html";
}
2.5 Spring+SpringMVC+Mybatis整合
2.5.1 创建项目导入jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>02-mvc01</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.2.0.RELEASE</spring.version>
</properties>
<dependencies>
<!--servlet-api-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!-- jsp-api -->
<dependency>
<groupId>javax.servlet.html</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<!-- jstl jar -->
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jstl-impl</artifactId>
<version>1.2</version>
</dependency>
<!-- spring相关jar -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- spring相关jar 结束 -->
<!-- mysql 数据库 jar -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<!-- mysql 数据库 end -->
<!-- mybatis 开始 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!-- mybatis 结束 -->
<!-- mybatis 和 spring的整合包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.4</version>
</dependency>
<!-- mybatis 和 spring的整合包 end -->
<!-- 日志 开始 -->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.3</version>
</dependency>
<!-- 日志 结束 -->
<!--pagehelper分页-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
<!-- 分页插件 结束 -->
<!-- lombok 开始 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
<!-- lombok 结束 -->
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
</project>
2.5.2 定义相关类
2.5.2.1 domain
package com.bjpowernode.domain;
import lombok.Data;
/**
* @Description: 用户类
*/
@Data
public class User {
private Integer id;
private String username;
private String password;
private String realname;
}
2.5.2.2 mapper
package com.bjpowernode.mapper;
import com.bjpowernode.domain.User;
import java.util.List;
/**
* @Description: 用户数据操作类
*/
public interface UserMapper {
/**
* 查询所有 用户信息
* @return
*/
List<User> selectAll();
}
2.5.2.3 service
package com.bjpowernode.service;
import com.github.pagehelper.PageInfo;
import com.bjpowernode.domain.User;
public interface IUserService {
/**
* 分页查询数据
* @param page
* @param limit
* @return
*/
PageInfo<User> queryPage(Integer page,Integer limit);
}
package com.bjpowernode.service.impl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.bjpowernode.domain.User;
import com.bjpowernode.mapper.UserMapper;
import com.bjpowernode.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @Description: 用户业务实现类
*/
@Service
public class UserServiceImpl implements IUserService {
@Autowired
private UserMapper userMapper;
/**
* 分页查询数据
* @param page
* @param limit
* @return
*/
@Override
public PageInfo<User> queryPage(Integer page, Integer limit) {
Page<User> pageObj = PageHelper.startPage(page, limit);
userMapper.selectAll();
return pageObj.toPageInfo();
}
}
2.5.2.4 controller
package com.bjpowernode.controller;
import com.github.pagehelper.PageInfo;
import com.bjpowernode.domain.User;
import com.bjpowernode.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
/**
* @Description: 用户控制类
*/
@Controller
@RequestMapping("user")
public class UserController {
@Autowired
private IUserService userService;
@RequestMapping("page.do")
public ModelAndView page(@RequestParam(name = "page",required = false,defaultValue = "1") Integer page, @RequestParam(name = "limit",required = false,defaultValue = "10") Integer limit){
PageInfo<User> pageInfo = userService.queryPage(page, limit);
ModelAndView modelAndView = new ModelAndView();
//设置视图路径
modelAndView.setViewName("/list.html");
//设置数据
modelAndView.addObject("pageInfo",pageInfo);
return modelAndView;
}
}
2.5.2.5 页面
<html>
<head>
<title>Title</title>
</head>
<body>
<table >
<thead>
<th>ID</th>
<th>username</th>
<th>password</th>
<th>realname</th>
</thead>
</table>
</body>
</html>
2.5.3 配置文件
2.5.3.1 数据库配置文件
#数据库连接信息
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/stmng?useUnicode=true&characterEncoding=utf8&useSSL=false
jdbc.username=root
jdbc.password=root
2.5.3.2 日志配置文件
# 全局日志配置
log4j.rootLogger=DEBUG, stdout
# MyBatis 日志配置
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
2.5.3.3 spring核心配置文件
<?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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 整合mybatis -->
<!--1. 引入数据库配置文件 因为创建数据源 -->
<context:property-placeholder location="classpath:jdbc.properties" system-properties-mode="FALLBACK" />
<!--2. 创建数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!--3. 创建SqlSessionFactoryBean -->
<!-- configuration 指 mybatis的核心配制信息 -->
<bean id="configuration" class="org.apache.ibatis.session.Configuration">
<property name="logImpl" value="org.apache.ibatis.logging.log4j.Log4jImpl"/>
<property name="cacheEnabled" value="true" />
</bean>
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 数据源 -->
<property name="dataSource" ref="dataSource"/>
<!-- 使用 configuration 取代了 mybatis的核心配置文件-->
<property name="configuration" ref="configuration"/>
<!-- 配置mapper 映射 文件-->
<property name="mapperLocations" value="classpath:mapper/**Mapper.xml" />
<!-- 配置类别名 -->
<property name="typeAliasesPackage" value="com.bjpowernode.domain" />
<!-- 配制插件 -->
<property name="plugins">
<array>
<!-- 分页插件 -->
<bean class="com.github.pagehelper.PageInterceptor" />
</array>
</property>
</bean>
<!--4. Mapper接口的扫描 自动创建代理类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 被扫描的mapper接口 产生接口的实现类 对象 使用SqlSession.getMapper(接口.class) -->
<property name="basePackage" value="com.bjpowernode.mapper" />
<!-- 注入一个SqlSessionFactoryBean 为了产生 SqlSession -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean" />
</bean>
<!-- 5. 配置事务 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 指定被管理事务的数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置声明式事务 XML 注解 -->
<!-- 开启事务注解 -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- 开启组件扫描 创建 对象 -->
<context:component-scan base-package="com.bjpowernode" />
</beans>
2.5.3.4 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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 开启组件扫描 -->
<!-- 扫描的目的是为了将 处理器放入到HandlerMapping中 -->
<context:component-scan base-package="com.bjpowernode.controller" />
<!-- 开启springmvc注解 -->
<mvc:annotation-driven />
</beans>
2.5.3.5 Mapper配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bjpowernode.mapper.UserMapper">
<select id="selectAll" resultType="User">
select * from user
</select>
</mapper>
2.5.3.6 web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 配置监听器需要加载的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-context.xml</param-value>
</context-param>
<!-- 加载初始化spring核心配置文件
配置监听器 启动时就加载 spring核心配置文件 IOC容器相关初始化
-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置 springmvc -->
<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>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
2.6 SpringMVC获取Servlet作用域
package com.bjpowernode.util;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* @Description: 获取Servlet 作用域对象工具类
* HttpServletRequest
* HttpSession
* ServletContext
*/
public class WebScopeUtil {
/**
* 获取当前 HttpServletRequest 对象
* @return
*/
public static HttpServletRequest getRequest(){
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
return requestAttributes.getRequest();
}
/**
* 获取当前请求绑定的session
* @return
*/
public static HttpSession getSession(){
return getRequest().getSession();
}
/**
* 获取全局容器对象
* @return
*/
public static ServletContext getContext(){
//getRequest().getServletContext(); // ServletContext 的生命周期 是早于 HttpServletRequest
//所以不能通过 HttpServletRequest 获取ServletContext 可能发生 NullpointException
return ContextLoader.getCurrentWebApplicationContext().getServletContext();
}
}
2.7 SpringMVC内置的编码过滤器
在springmvc中,为了解决乱码问题,springmvc提供了内置的编码过滤器。在使用时,只需要在web.xml中进行配置即可。
<!-- 编码过滤器 -->
<filter>
<filter-name>charsetFilter</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>charsetFilter</filter-name>
<!-- 只对springmvc处理的请求进行编码过滤 -->
<servlet-name>springmvc</servlet-name>
</filter-mapping>
2.8 SpringMVC返回JSON
{key1:value1,key2:value2}:key为String,value为Object
[{},{},{}…]
实体类对象、Map<String,Object>、List<实体类>、List<Map<String,Object>>
fastjson.jar: JSON.toJSONString(Object)
在springmvc中,默认返回的数据不论是什么格式,都当做视图进行解析。会根据返回值的toString的结果,当做路径去查找视图的模板,如果想要返回JSON,则需要使用注解,标识该方法返回的是JSON数据,不要当做视图路径进行路径的查找.该注解为:@ResponseBody.因为springmvc有内置的消息转换器,如果想要特殊设置,需要进行XML配置.
2.8.1 XML配置的形式
XML配置形式,是修改了默认结果处理,全局生效的。使用注解@ResponseBody,标识该方法返回的内容不是URL地址,而是一个消息,使用输出对象输出给客户端。
@RequestMapping
name : 方法映射名称
value/path : 方法访问路径
method : 支持的请求的方法类型:
GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE
params : 请求必须有的参数
headers : 请求必须有的头信息
consumes : 指定请求的数据格式类型 : 普通文本、表单格式、JSON
produces : 指定返回数据的格式类型 :JSON 、HTML
<!-- 配置JSON转换器 -->
<!--<bean id="config" class="com.alibaba.fastjson.support.config.FastJsonConfig">-->
<!--</bean>-->
<mvc:annotation-driven >
<mvc:message-converters register-defaults="true">
<!--
将内容转化为字符串消息 使用 IO发送给客户端
此时只支持字符串
-->
<!--<bean class="org.springframework.http.converter.StringHttpMessageConverter" />-->
<!-- 将内容转化为JSON字符串 发送客户端 能够处理对象-->
<!-- date 年-月-日 时:分:秒 -->
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter" />
</mvc:message-converters>
</mvc:annotation-driven>
2.8.2 注解
SpringMVC中,有内置的转换器,但是SpringMVC内置的转换器需要相关jar包,需要jackson的jar包。只需要导入jar包后,使用@ResponseBody标识返回的数据是消息即可。SpringMVC自动将返回数据当做JSON字符串处理,并且消息按照UTF-8进行编码。如果@ResponseBody放在类上,类中所有的方法都返回的是消息,不是视图资源。
注意:
@RestController
是 @ResponseBody, @Controller 结合,标识该类是一个处理器,并且处理器中所有的方法都返回的是消息。
<!-- 导入jackson的jar包 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.11.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.11.2</version>
</dependency>
2.9 文件上传下载
在springmvc中,也对文件上传进行了封装。更进一步的简化的文件上传,只需导入文件上传相关的jar包和处理文件上传的解析器即可。
2.9.1 文件上传
2.9.1.1 导入jar包
<!-- 文件上传相关依赖jar -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
2.9.1.2 配置文件上传的解析器
在SpringMVC的核心配置文件中,新增文件上传解析器配置:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--文件格式编码-->
<property name="defaultEncoding" value="UTF-8"></property>
<!--配置单个文件上传大小:1M-->
<property name="maxUploadSizePerFile" value="1048576"></property>
<!--配置所有文件上传总大小:10M-->
<property name="maxUploadSize" value="10485760"></property>
</bean>
2.9.1.3 处理文件上传请求
页面
<html>
<head>
<title>文件上传</title>
</head>
<body>
<form action="file/upload2.do" method="post" enctype="multipart/form-data">
<p>
普通的文本数据:<input name="name" type="text" />
</p>
<p>
文件数据:<input name="userImg" type="file" />
</p>
<p>
文件数据:<input name="userImg" type="file" />
</p>
<input type="submit" value="提交">
</form>
</body>
</html>
处理器
package com.bjpowernode.controller;
import cn.hutool.core.img.Img;
import cn.hutool.core.img.ImgUtil;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import java.awt.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@Controller
@RequestMapping("file")
public class FileUploadController {
/**
* 如果是单个文件,则直接使用MultipartFile 对象进行接收
* 普通的文本数据 则直接使用相应的类型进行接收
* 如果名字不一致 @RequestParam 注解 处理名称
* @param name
* @param file
* @return
*/
@RequestMapping("upload1.do")
public String upload1(String name,@RequestParam("userImg") MultipartFile file){
System.out.println("文本数据为:"+name);
System.out.println("文件数据为:"+file.getName());//input name 属性值
System.out.println("文件数据为:"+file.getSize()); // 文件的字节大小
System.out.println("文件数据为:"+file.getOriginalFilename()); //文件的真实名称
return "/success.html";
}
/**
* 如果是多个文件 则使用MultipartFile[] 数组进行接收
* @param name
* @param files
* @return
*/
@RequestMapping("upload2.do")
public String upload2(String name,@RequestParam("userImg") MultipartFile[] files){
System.out.println("文本数据为:"+name);
for (MultipartFile file : files) {
System.out.println("文件数据为:"+file.getName());//input name 属性值
System.out.println("文件数据为:"+file.getSize()); // 文件的字节大小
System.out.println("文件数据为:"+file.getOriginalFilename()); //文件的真实名称
//将文件进行保存
File newFile = new File("d://"+file.getOriginalFilename());
try {
Font font = new Font("微软雅黑",Font.BOLD,15);
ImgUtil.pressText(file.getInputStream(),new FileOutputStream(newFile),"我是水印", Color.RED,font,1,1,0.5f);
//将文件保存在磁盘上
//file.transferTo(newFile);
} catch (IOException e) {
e.printStackTrace();
}
}
return "/success.html";
}
}
/**
* 一个file控件同时上传多个
* MultipartFile代表一个文件 MultipartRequest:封装了多个MultipartFile对象
*/
@RequestMapping("/uploadMany2.do")
public void uploadMany2(MultipartRequest mr) throws IOException {
List<MultipartFile> fileList = mr.getFiles("f");
for (int i = 0;fileList!=null && i < fileList.size(); i++) {
MultipartFile tempFile = fileList.get(i);
//将上传的文件保存到D:\\uploads\\
String name = tempFile.getOriginalFilename();//获取上传文件的名字 1.2.3.jpg 1.jpg 1.avi C:\\users\\desktop\\1.jpg
//获取上传文件的拓展名
int index = name.lastIndexOf(".");
String ext = name.substring(index);//.jpg .avi .pptx
//将上传的文件保存到指定目录
String fileName = UUID.randomUUID().toString();
File file = new File("D:\\uploads\\"+fileName+ext);
tempFile.transferTo(file);
}
}
2.9.2 文件下载
2.9.2.1 方案一(推荐):
文件下载的本质,就是获取服务器的文件数据信息,使用字节流将数据传递给客户端。
-
使用输入流,将磁盘文件读到内存中。
-
使用网络输出流,将数据输出给客户端。
package com.bjpowernode.controller;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URLEncoder;
/**
* @Description: 文件下载示例
*/
@Controller
@RequestMapping("download")
public class DownLoadController {
/**
* 文件下载的方法
*/
@RequestMapping("download.do")
public void download(HttpServletResponse response) throws Exception {
File file = new File("E:\\猪图片.jpg");//本地磁盘文件
//使用输入流 将文件读入内存中
FileInputStream fis = new FileInputStream(file); // 找参照物 将程序运行的内存当做参照物
byte[] b = new byte[1024];
int len = -1;
ServletOutputStream out = response.getOutputStream();//输出流 输出客户端
//浏览器 默认打开了这个文件
//设置响应类型 通知浏览器 不要打开
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
//文件的名称 不对
//设置响应的文件的名称
//如果响应的数据的名称是中文,在设置文件的名称时 要先将文件的名称进行编码 再进行传输
String name = URLEncoder.encode("猪图片.jpg", "UTF-8");
System.out.println("编码后的名字:"+name);
response.setHeader("Content-Disposition", "attachment; filename="+name);
//循环读 循环写
while((len = fis.read(b)) != -1) {
out.write(b,0,len);
out.flush();
}
out.close();
fis.close();
}
}
2.9.2.2 方案二:
springMVC中为了简化文件的下载,封装了实体类:ResponseEntity,可以将文件数据封装在ResponseEntity中。
package com.bjpowernode.controller;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URLEncoder;
/**
* @Description: 文件下载示例
*/
@Controller
@RequestMapping("/download")
public class DownLoadController {
@RequestMapping("/download2.do")
public ResponseEntity<Byte[]> download() throws Exception {
File file = new File("E:\\猪图片.jpg");//本地磁盘文件
//使用输入流 将文件读入内存中
FileInputStream fis = new FileInputStream(file); // 找参照物 将程序运行的内存当做参照物
//文件的大小
long length = file.length();
//创建一个和文件一样大小的字节数组 一次性将数据读入到内存中 如果文件量过大,请求比较频繁 存在 崩溃的风险
byte[] fileByte = new byte[(int) length];//一个G 的 byte 数组 64 G 65个人下载 1分钟
//一次性将文件数据读入到数组中
fis.read(fileByte);
// springmvc 中封装的 响应实体 :
//设置响应码
//设置响应的数据头信息
//设置响应数据
HttpHeaders headers = new HttpHeaders(); //响应头信息
//设置响应的数据为流数据 告诉浏览器 不要解析
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
//设置下载的文件的名称 中文字符串要进行编码
headers.setContentDispositionFormData("filename","猪图片.jpg");
ResponseEntity responseEntity = new ResponseEntity(fileByte,headers, HttpStatus.OK);
return responseEntity;
}
}
2.10 SpringMVC中的拦截器
SpringMVC提供HandlerInteceptor接口,这个接口用于拦截处理具体的Handler中的方法,在具体的Handler中的方法执行前后及返回视图之间都可以进行相关扩展操作。
2.10.1 如何使用拦截器
2.10.1.1 创建类实现HandlerInteceptor接口
package com.bjpowernode.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Description: 自定义拦截器
*/
public class MyInterceptor implements HandlerInterceptor {
/**
* 在执行具体的Handler中的方法前执行
* @param request 当前的请求对象
* @param response 当前的响应对象
* @param handler 具体的处理器中将要执行的方法
* @return boolean 如果 返回 true 则执行Handler中的方法 false 则 不执行handler中的方法
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("我是拦截器中preHandle 方法");
return true;
}
/**
* 在具体的Handler中的方法执行完成 但是没有做具体的视图解析操作
* @param request 当前 请求对象
* @param response 当前响应对象
* @param handler 具体的处理器中将要执行的方法
* @param modelAndView 具体的处理器中将要执行的方法 返回的结果
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("我是拦截器中postHandle 方法");
//在具体的解析之前 修改视图模型中数据
modelAndView.addObject("name","韩梅梅");
}
/**
* 完成了视图解析后 整个方法执行完成调用的方法 在finally中调用 或者出现异常也会调用
* @param request 当前请求对象
* @param response 当前响应对象
* @param handler 具体的处理器中将要执行的方法
* @param ex 具体的处理器中抛出的异常
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("我是拦截器中afterCompletion 方法");
System.out.println(ex.getMessage());
request.setAttribute("msg","网管去火星了!");
request.getRequestDispatcher("/500.html").forward(request,response);
}
}
2.10.1.2 配置拦截器
<?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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 开启组件扫描 -->
<!-- 扫描所有处理器 放入到处理器映射器中 -->
<context:component-scan base-package="com.bjpowernode.controller" />
<!-- 开启 mvc注解 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 文件上传的解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" >
<!--<property name="maxUploadSize" value="1"></property>-->
</bean>
<!-- 配置springmvc的拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 拦截器的资源路径 /** 拦截所有 ** 表示多层目录 -->
<mvc:mapping path="/**"/>
<!-- 不拦截的资源路径 -->
<mvc:exclude-mapping path="/user/page.do"/>
<!-- 自定义的拦截器 -->
<bean id="myInterceptor" class="com.bjpowernode.interceptor.MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
</beans>
注意:
-
在拦截器中,最先执行preHandle,然后执行Handler中具体的方法,再然后执行postHandle和afterCompletion。preHandle就是前置的拦截的方法,返回如果为true,则执行处理器中的方法,如果为false则不执行处理器中的方法。postHandle是在Handler中具体的方法执行完成,但是没有交给视图解析器之前执行,afterCompletion在视图解析器完成了视图解析之后执行的。
-
拦截器是拦截器的方法,被DispatcherServlet代理调用的方法,如果请求的不是Handler,拦截器是不会拦截的。index.html由于是由tomcat默认的servlet进行返回的,不会执行DispatcherServlet中的doDispatch,那么拦截器无法进行拦截。
2.10.2 Interceptor和Filter的区别
Filter是Java Web的规范,拦截的是请求,任何JavaWeb项目都可以有Filter,但是Interceptor是SpringMVC提供的一套规范HandlerInterceptor,只适用SpringMVC自身,并且只能对DispatherServlet处理器的请求生效,拦截的方法。从范围上说,任何JavaWeb项目都有Filter,但是未必有Interceptor。
1、filter可以应用于任何的javaweb项目;inteceptor应用于springmvc框架
2、Filter可以过滤所有请求资源(不限于html、css、js、images等);Interceptor只能拦截所有的controller方法
3、Filter过滤路径时,没有排除选项;Interceptor可以排除拦截路径
2.11 异常处理器
在spring中,相对完善的异常处理器机制,spring可以自己定义处理异常的规则,这种处理异常规则的程序,就被称之为异常处理器。其实,异常处理器就是对controller的增强,因为异常是向上抛,controller调用service,service调用mapper,controller属于最上层,所以最终异常都会汇集到controller。因此,spring提供了@ControllerAdvice注解,表示对controller增强类。并且还提供了@ExceptionHandler这个注解,当发生异常时,该注解修饰的方法就会执行。
在实际开发中,异常主要分为两类:
-
系统异常,JDK中定义的异常
-
业务异常,开发者自己定义的异常
一般是将系统异常转化为业务异常,开发者只处理业务异常。使用try…catch…将代码包裹起来,在catch中抛出自定义的异常,这种方案就是将系统异常转化为业务异常。因为很多数据操作,事务需要异常进行数据回滚。
package com.bjpowernode.handler;
import com.bjpowernode.exception.BussiException;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
/**
* @Description: 全局异常处理器
*/
@ControllerAdvice
public class GlobalExceptionHandler {
/**
* 具体的异常处理方法
* @param exception
*/
@ExceptionHandler
public void doException(Exception exception){
//exception FileNotFound indexOutof xxxx
//判断 异常类型是不是自定义异常
if (exception instanceof BussiException){
BussiException ex = (BussiException) exception;
Integer code = ex.getCode();//获取异常码
String msg = ex.getMsg();//获取异常消息
System.out.println(code +":"+msg);
//Result 转化为JSON字符串 将JSON字符串返回给客户端
}
}
}
package com.bjpowernode.exception;
/**
* @Description: 自定义异常
*/
public class BussiException extends RuntimeException {
private Integer code;//异常码
private String msg;//异常消息
public BussiException(){}
public BussiException(Integer code,String msg){
super(msg);
this.code = code;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
package com.bjpowernode.controller;
import com.bjpowernode.exception.BussiException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/test")
public class TestController {
@RequestMapping("/test.do")
public String test(){
//数据校验 可能发生的情况 很多种
int m = 0;
try {
System.out.println(100/m);
}catch (Exception e){
e.printStackTrace();//打印异常
//自己抛出了异常
throw new BussiException(1001,"被除数不能为0");
}
return "/success.html";
}
}
2.12 springmvc中数据校验
springmvc中的数据校验时通过hibernate-validator实现,对实体类中的字符串有效。
1、引入hibernate-validator依赖
2、在实体类中的字符串(正则表达式)属性上添加相关注解
3、可以用hibernate-validor提供的特有注解对Long、Integer、Float做校验
4、在被校验的实体类前添加@Valid注解
5、当实体类中的数据格式发生错误时,错误信息被封装到了BindResult对象中去,BindResult必须和实体类紧紧挨在一起
2.13 Restful风格
Restful风格适合参数少、参数不敏感的请求地址。使用了restful风格的请求地址,就不能使用.do的方式请求
Resustful风格:
-
请求地址问题
-
请求方式问题
http://localhost:8080/getBooksByFenye.do?pageNum=1&pageSize=5
http://localhost:8080/getBooksByFenye/1/5
2.13.1 Http协议设计的初衷
HTTP协议在设计时,期望使用一个URL表示一个资源。然后,根据不同的动作:GET、POST、PUT、DELETE等等表示对一个资源的各种操作。
如:
获取这个资源就使用GET, @GetMapping(“/”)
修改这个资源PUT, @PutMapping()
删除这个资源用DELETE,@DeleteMapping()
创建这个资源使用POST。 @PostMapping()
但是在实际使用中,多个URL表示一个资源,例如:新增用户: addUser.do,修改用户:updateUser.do,删除用户:deleteUser.do,查询一个用户:getUser.do。这时候,出现一个资源存在多个URL。在一定程度声,违背了HTTP协议的设计初衷,并且命名也是个问题。
2.13.2 Restful设计思想
-
使用一个URL表示一种资源
-
客户端使用GET、POST、PUT、DELETE4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源
-
通过操作资源的表现形式来操作资源
2.13.3 在SpringMVC中使用Restful
SpringMVC也支持Restful风格,但是目前存在一些问题。主要不是很好支持PUT请求,没有办法获取到PUT请求的数据。
2.13.3.1 将DispatherServlet的映射地址改为
由于将DispatherServlet的映射路径,改为了/,则所有的请求都由DispatherServlet处理,静态的资源文件不在处理器映射器中,会出现404。并拦截器拦截DispatherServlet中调用Handler中的方法,改为/,则所有的请求都会被拦截。
则需要在SpringMVC的核心配置文件中,新增启用默认的Servlet的处理器。
<!-- 启用默认Servlet -->
<mvc:default-servlet-handler/>
并且注意,配置拦截器时,将静态资源不进行拦截,要排除:
<mvc:exclude-mapping path="/resouces/**"/>
2.13.3.2 配置处理PUT请求的拦截器
<!-- 处理put请求的拦截器 -->
<filter>
<filter-name>restful</filter-name>
<filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>restful</filter-name>
<servlet-name>springmvc</servlet-name>
</filter-mapping>
2.13.3.3 处理器代码
package com.bjpowernode.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("user")
public class UserController {
// @RequestMapping(method = RequestMethod.GET)
// //@GetMapping
// public Object get(Integer id){
// System.out.println("get请求");
// Map<String,Object> data = new HashMap<>();
// data.put("code",200);
// data.put("msg","get请求");
// return data;
// }
@GetMapping("{id}/{name}") //后台的获取方式 使用 {} 进行包裹 并且 在方法参数中 使用@PathVariable
// 这种将参数拼接在URL上的方式 只支持 GET 请求和 DELETE请求
public Object get1(@PathVariable("id") Integer id,@PathVariable("name") String name){
System.out.println("get请求");
System.out.println(id);
System.out.println(name);
Map<String,Object> data = new HashMap<>();
data.put("code",200);
data.put("msg","get请求");
return data;
}
//@RequestMapping(method = RequestMethod.PUT)
@PutMapping
public Object put(Integer id){
System.out.println("PUT请求");
Map<String,Object> data = new HashMap<>();
data.put("code",200);
data.put("msg","PUT请求");
return data;
}
@RequestMapping(method = RequestMethod.POST)
@PostMapping
public Object post(Integer id){
System.out.println("post请求");
Map<String,Object> data = new HashMap<>();
data.put("code",200);
data.put("msg","post请求");
return data;
}
//@RequestMapping(method = RequestMethod.DELETE)
@DeleteMapping
public Object delete(Integer id){
System.out.println("delete请求");
Map<String,Object> data = new HashMap<>();
data.put("code",200);
data.put("msg","delete请求");
return data;
}
}
2.13.3.4 页面代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button id="btn1">get</button>
<button id="btn2">put</button>
<button id="btn3">delete</button>
<button id="btn4">post</button>
<button id="btn5">get-1111</button>
<script src="resources/jquery.js"></script>
<script>
$("#btn1").click(function () {
$.get("user",{id:1001},function (rs) {
console.log(rs);
})
});
$("#btn2").click(function () {
$.ajax({
url:"user",
type:"PUT",
data:{id:1001},
success:function (rs) {
console.log(rs);
}
})
});
$("#btn3").click(function () {
$.ajax({
url:"user",
type:"DELETE",
data:{id:1001},
success:function (rs) {
console.log(rs);
}
})
});
$("#btn4").click(function () {
$.post("user",{id:1001},function (rs) {
console.log(rs);
})
});
$("#btn5").click(function () {
//将参数 拼接在URL上面
$.get("user/11111/lucy",function (rs) {
console.log(rs);
})
});
</script>
</body>
</html>