目录
2.编写文件解析器,并交给SringMVC管理(第三方bean)使用注解@Bean
第二步:让SpringMVC开启辅助功能,如日期类型转换,json类型转换
第三步:编写Controller类,并使用注解@RequestBody,一个方法只能使用一次(解析前端传来的json对象)
SpringMVC概述
MVC(Model View Controller),一种用于创建web应用程序的表现层的模式
1.Model(模型):数据模型,用于封装数据
2.View(视图):页面视图,用于展示数据
- jsp
- html
3.Controller(控制器):处理用户交互的调度器,用于根据用户需求处理程序逻辑
SpringMVC快速入门
第一步:创建Maven工程,并导入相关的依赖
springMVC的依赖
<!-- springMVC的依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.10.RELEASE</version> </dependency>
servlet-api
注意:需要指定作用范围
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <!-- 需要指定作用范围--> <scope>provided</scope> </dependency>
我们可以发现springMVC的依赖包括了spring-context的依赖
第二步:创建控制器类
/* 1.需要交给spring管理 2.定义处理请求的方法 3.设置当前方法的访问路径 4.设置返回数据类型为String */ @Controller public class UserController { @RequestMapping("/save") @ResponseBody public String save(){ System.out.println("user save"); return "springMVC"; } }
创建控制器类也需要四步:
第一步:需要交给spring管理,即添加@Controller注解
第二步:定义处理请求的方法-->public String save()
第三步:设置当前方法的访问路径-->使用注解@RequestMapping("/save")
第四步:设置返回数据类型为String-->使用注解@ResponseBody
第三步:初始化SpringMVC环境
这是一个设置扫描范围的配置类(主配置类)
@Configuration @ComponentScan("com.hhh") public class SpringMvcConfig { }
第四步:创建Tomcat的Servlet容器配置类
public class ServletContainerInitConfig extends AbstractDispatcherServletInitializer { //创建SpringMVC容器(spring容器) @Override protected WebApplicationContext createServletApplicationContext() { //ApplicationContext ctx =new AnnotationConfigApplicationContext(); //加载配置类,创建SpringMVC容器 AnnotationConfigWebApplicationContext ctx =new AnnotationConfigWebApplicationContext(); ctx.register(SpringMvcConfig.class); return ctx; } //设置哪些请求交给springMVC管理 @Override protected String[] getServletMappings() { //这里设置了所有请求都交给SpringMVC管理 return new String[]{"/"}; } //创建Spring容器 @Override protected WebApplicationContext createRootApplicationContext() { return null; } }
第五步:导入tomcat插件,并设置war方式打包
<build> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.1</version> <configuration> <!-- 指定端口 --> <port>8080</port> <!-- 请求路径 --> <path>/</path> <!-- <!–这个名称需要,在maven插件中显示应用名称–>--> <!-- <server>tomcat7</server>--> </configuration> </plugin> </plugins> </build>
<packaging>war</packaging>
完整pom.xml
<?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>com.hhh</groupId> <artifactId>spring_day6_MVC</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <maven.compiler.source>21</maven.compiler.source> <maven.compiler.target>21</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <!-- 需要指定作用范围--> <scope>provided</scope> </dependency> <!-- springMVC的依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.10.RELEASE</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.1</version> <configuration> <!-- 指定端口 --> <port>8080</port> <!-- 请求路径 --> <path>/</path> <!-- <!–这个名称需要,在maven插件中显示应用名称–>--> <!-- <server>tomcat7</server>--> </configuration> </plugin> </plugins> </build> </project>
第六步:启动
点击加号,选择maven,然后再Run里填写tomcat7:run,最后点击apply
结果:
测试
启动成功
注意:需要在main目录下面新建一个webapp目录
请求路径优化
添加一个新的类
@Controller public class BookController { @RequestMapping("/save") @ResponseBody public String save(){ System.out.println("book save"); return "bookSpringMVC"; } }
请求路径与之前的一样,会报错
所以这样添加目录
但是这样子每个方法都要添加一级目录,比较麻烦,所以我们可以在这个类上使用注解@RequestMapping注解
@Controller @RequestMapping("/book") public class BookController { @RequestMapping("/save") @ResponseBody public String save(){ System.out.println("book save"); return "bookSpringMVC"; } }
@Controller @RequestMapping("/user") public class UserController { @RequestMapping("/save") @ResponseBody public String save(){ System.out.println("user save"); return "springMVC"; } }
测试:
指定请求方法
现在我们使用的式@RequestMapping注解,这个注解支持GET,POST请求,但是我们要指定请求方法要怎么做呢?
@Controller @RequestMapping("/book") public class BookController { @RequestMapping(value = "/save",method = RequestMethod.GET)//这样子只能使用GET请求 @ResponseBody public String save(){ System.out.println("book save"); return "bookSpringMVC"; } }
请求参数处理
六种常规类型
第一种:普通请求参数
请求参数的key值与方法的形参名一致
后端:
@Controller public class ParamController { //普通类型参数 @RequestMapping("/commonParam") @ResponseBody public String commonParam(@RequestParam("name") String username, Integer age){//请求参数名和变量名一致即可 System.out.println("username="+username); System.out.println("age="+age); return "CommonParam"; } }
使用postman向后端发送请求
如果前端请求参数名字与后端形参名不一致时,使用@RequestParam注解。
SpringMVC会自动把String类型的age转换成Integer类型
第二种:pojo类型请求参数
pojo类的成员变量名字与前端的key值一致
User类
public class User { private String name; private Integer age; private Address address; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + ", address=" + address + '}'; } }
Address类型
public class Address { private String province; private String city; public String getProvince() { return province; } public void setProvince(String province) { this.province = province; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } @Override public String toString() { return "Address{" + "province='" + province + '\'' + ", city='" + city + '\'' + '}'; } }
后端:
@Controller public class ParamController { //pojo嵌套类型 @RequestMapping("/pojoContainPojoParam") @ResponseBody public String pojoContainPojoParam(User user){ System.out.println(user); return "pojoContainPojoParam"; }
前端:
可以发现如果成员变量也是pojo类型,就要使用成员变量名.成员变量名的方法
结果:
原理:SpringMVC会使用构造器实例化出一个pojo类对象,即User对象(new User()),然后使用User类里的setXxx()方法进行赋值,如果没有构造器会报错,没有set方法那么这个成员变量就为空null值
如果使用注解@RequestParam
就会报错:
因为@RequestParam是直接把请求参数与形参进行绑定,并直接赋值,这样一来User类型对象并没有实例化,所以就会报错
第三种:数组类型请求参数
前端使用多个相同名字的key值与形参变量名一致
@Controller public class ParamController { //数组类型 @RequestMapping("/arrayParam") @ResponseBody public String arrayParam(String[]list){ System.out.println(Arrays.toString(list)); return "arrayParam"; } }
前端:
结果:
第四种:List集合类型
@Controller public class ParamController { //集合类型 @RequestMapping("/listParam") @ResponseBody public String listParam(@RequestParam List<String>list){ //因为List不是简单类型,所以springMVC会直接把List看成pojo类型,然后会实例化list,但是List集合没有构造器,就会报错 //所以添加@RequestParam注解,这样一来spring会直接给list赋值,而不是实例化去使用set()方法 System.out.println(list); return "listParam"; } }
前端:
可以发现我们后端的形参中使用了@RequestParam注解,因为这个注解的作用就是绑定形参变量,直接进行赋值,因为List集合不是简单类型,所以SpringMVC会把List集合看出pojo类型,会先实例化List集合再进行set方法赋值,但是List集合并没有构造器,因此不加@RequestParam注解就会报错:
第五种:map集合类型
@Controller public class ParamController { //map集合类型 @RequestMapping("/mapParam") @ResponseBody public String mapParam(@RequestParam Map<String,String> map){ //@RequestParam把请求参数与形参绑定,直接赋值 //System.out.println(map); map.forEach((key,value)-> System.out.println(key+"->"+value)); return "mapParam"; } }
前端:
结果:
日期请求参数传递
@Controller public class DateController { @RequestMapping("/dateParam") @ResponseBody public String dateParam(Date date){ System.out.println(date); return "dateParam"; } }
前端:
结果:
可以发现时期使用的是/来间隔,如果使用-来间隔,会报错:
不能把String类型转换成Date类型,所以我们要使用注解@DateTimeFormat的pattern属性来指定日期类型格式
@Controller public class DateController { @RequestMapping("/dateParam") @ResponseBody public String dateParam(Date date,@DateTimeFormat(pattern = "yyyy-MM-dd") Date date1){ System.out.println(date); System.out.println(date1); return "dateParam"; } }
如果要运行成功,还需要再主配置类中添加@EnableWebMvc,让SpringMVC开启辅助功能
@Configuration @ComponentScan("com.hhh") @EnableWebMvc//让SpringMVC开启辅助功能 public class SpringMvcConfig { }
结果:
文件类型参数传递
1.先导入依赖
<!-- 文件解析的依赖--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency>
2.编写文件解析器,并交给SringMVC管理(第三方bean)使用注解@Bean
@Configuration @ComponentScan("com.hhh") @EnableWebMvc//让SpringMVC开启辅助功能 public class SpringMvcConfig { //配置文件解析器,并交给SpringMVC管理 @Bean("multipartResolver")//这个解析器类型的Bean id必须是multipartResolver,源码是通过id名来获取bean的 public MultipartResolver multipartResolver(){ CommonsMultipartResolver commonsMultipartResolver=new CommonsMultipartResolver(); commonsMultipartResolver.setMaxUploadSize(1024*1024);//单位是字节(byte) //设置文件最大为1MB return commonsMultipartResolver; } }
注意:这个解析器类型的Bean id必须是multipartResolver,源码是通过id名来获取这个类型的bean
后端
@Controller public class FileController { @RequestMapping("/fileParam") @ResponseBody public String fileParam(MultipartFile file) throws IOException { if(!file.isEmpty()){ file.transferTo(new File("D://test.txt"));//把文件另存为 } return "fileParam"; } }
前端
请求方法只能选择post,文件类型要选择form-data,其他类型选择的是右边那个长的
结果:
D盘出现该文件,成功
JSON类型参数传递
第一步:导入解析json对象的依赖
<!-- 解析json的依赖--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency>
第二步:让SpringMVC开启辅助功能,如日期类型转换,json类型转换
@Configuration @ComponentScan("com.hhh") @EnableWebMvc//让SpringMVC开启辅助功能,如日期类型转换,json类型转换 public class SpringMvcConfig { //配置文件解析器,并交给SpringMVC管理 @Bean("multipartResolver")//这个解析器类型的Bean id必须是multipartResolver,源码是通过id名来获取bean的 public MultipartResolver multipartResolver(){ CommonsMultipartResolver commonsMultipartResolver=new CommonsMultipartResolver(); commonsMultipartResolver.setMaxUploadSize(1024*1024);//单位是字节(byte) //设置文件最大为1MB return commonsMultipartResolver; } }
第三步:编写Controller类,并使用注解@RequestBody,一个方法只能使用一次(解析前端传来的json对象)
@Controller public class JsonController { @RequestMapping("/pojoParamForJson") @ResponseBody public String pojoParamForJson(@RequestBody User user){ System.out.println(user); return "pojoParamForJson"; } }
前端
结果:
数组类型的pojo类型
@RequestMapping("/arrayPojoParam") @ResponseBody public String arrayPojoParam(@RequestBody List<User>list){ System.out.println(list); return "arrayPojoParam"; }
前端
数组使用[]
结果
处理中文请求乱码问题
1.GET请求乱码问题
<build> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.1</version> <configuration> <!-- 指定端口 --> <port>8080</port> <!-- 请求路径 --> <path>/</path> <!-- <!–这个名称需要,在maven插件中显示应用名称–>--> <!-- <server>tomcat7</server>--> <uriEncoding>utf-8</uriEncoding> </configuration> </plugin> </plugins> </build>
添加<uriEncoding>utf-8</uriEncoding>
2.解决POST请求乱码
为web容器添加过滤器并指定字符集
public class ServletContainerInitConfig extends AbstractDispatcherServletInitializer { //创建SpringMVC容器(spring容器) @Override protected WebApplicationContext createServletApplicationContext() { //ApplicationContext ctx =new AnnotationConfigApplicationContext(); //加载配置类,创建SpringMVC容器 AnnotationConfigWebApplicationContext ctx =new AnnotationConfigWebApplicationContext(); ctx.register(SpringMvcConfig.class); return ctx; } //设置哪些请求交给springMVC管理 @Override protected String[] getServletMappings() { //这里设置了所有请求给SpringMVC管理 return new String[]{"/"}; } //创建Spring容器 @Override protected WebApplicationContext createRootApplicationContext() { return null; } //设置参数编码为utf-8,解决post请求乱码 @Override protected Filter[] getServletFilters() { CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); characterEncodingFilter.setEncoding("UTF-8"); return new Filter[]{characterEncodingFilter}; } }
添加
//设置参数编码为utf-8,解决post请求乱码
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
return new Filter[]{characterEncodingFilter};
}
响应数据
响应一个页面
创建一个jsp文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <div>hello</div> </body> </html>
@Controller public class ResponseController { //不加@ResponseBody就会去找页面名为page.jsp的页面 @RequestMapping("/toPage") public String toPage(){ System.out.println("toPage"); return "page.jsp"; } }
如果加了@ResponseBody
@RequestMapping("/toText") @ResponseBody public String toText(){ System.out.println("toText"); return "page.jsp"; }
返回的就是字符串本身
所以@Response注解(使用在方法上)的作用就是设置当前控制器的返回值作为响应体。
不加这个注解就会去找对应名字的页面,并返回给前端
响应JSON对象,也要使用@Response注解
返回类型是对象
@Controller public class ResponseController { @RequestMapping("/toJson") @ResponseBody public User toJson(){ User user = new User(); user.setName("hhh"); user.setAge(19); Address address = new Address(); address.setProvince("河北"); address.setCity("石家庄"); user.setAddress(address); return user; } }
响应JSON对象数组
@Controller public class ResponseController { @RequestMapping("/toJsonArray") @ResponseBody public List<User> toJsonArray(){ User user1 = new User(); user1.setName("hhh"); user1.setAge(19); Address address = new Address(); address.setProvince("河北"); address.setCity("石家庄"); user1.setAddress(address); User user2 = new User(); user2.setName("aaa"); user2.setAge(19); Address address2 = new Address(); address2.setProvince("河北"); address2.setCity("石家庄"); user2.setAddress(address2); List<User>list=new ArrayList<>(); Collections.addAll(list,user1,user2); return list; } }
注意:跟解析请求JSON对象一样,也要导入json解析所需要的依赖,也需要使用注解@EnableWebMvc//让SpringMVC开启辅助功能,如日期类型转换,json类型转换
RESful风格
@Controller public class UserController { //新增,保存操作 @RequestMapping(value = "/users",method = RequestMethod.POST) @ResponseBody public String save(){ return "save"; } //修改,更新 @RequestMapping(value = "/users",method = RequestMethod.PUT) @ResponseBody public String update(){ return "update"; } //查询全部 @RequestMapping(value = "/users",method = RequestMethod.GET) @ResponseBody public String getAll(){ return "getAll"; } //查询某一个 @RequestMapping(value = "/users/{id}",method = RequestMethod.GET) @ResponseBody public String getById(@PathVariable("id") Integer id){//通过请求路径获取值,而不是通过请求参数 System.out.println("id="+id); return "getById"; } //删除某一个 @RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE) @ResponseBody public String delete(@PathVariable("id") Integer id){ System.out.println("id="+id); return "delete"; } }
我们可以发现每个@RequestMapping都要写/users,比较麻烦,我们可以直接在类上使用注解 @RequestMapping
每个方法都要写@Response比较麻烦,我们可以直接在类上使用注解 @ResponseBody
@Controller @RequestMapping("/users") @ResponseBody public class UserController { //新增,保存操作 @RequestMapping(method = RequestMethod.POST) public String save(){ return "save"; } //修改,更新 @RequestMapping(method = RequestMethod.PUT) public String update(){ return "update"; } //查询全部 @RequestMapping(method = RequestMethod.GET) public String getAll(){ return "getAll"; } //查询某一个 @RequestMapping(value = "/{id}",method = RequestMethod.GET) public String getById(@PathVariable("id") Integer id){//通过请求路径获取值,而不是通过请求参数 System.out.println("id="+id); return "getById"; } //删除某一个 @RequestMapping(value = "/{id}",method = RequestMethod.DELETE) public String delete(@PathVariable("id") Integer id){ System.out.println("id="+id); return "delete"; } }
然后我们还发现每个@RequsetMapping都要写一个method属性来指定请求方法,比较麻烦,所以,Post请求就使用@PostMapping,以此类推
@ResponseBody和@Controller这两个注解放在一起可以使用@RestController注解来替代
//@Controller //@ResponseBody @RestController @RequestMapping("/users") public class UserController { //新增,保存操作 //@RequestMapping(method = RequestMethod.POST) @PostMapping public String save(){ return "save"; } //修改,更新 //@RequestMapping(method = RequestMethod.PUT) @PutMapping public String update(){ return "update"; } //查询全部 // @RequestMapping(method = RequestMethod.GET) @GetMapping public String getAll(){ return "getAll"; } //查询某一个 //@RequestMapping(value = "/{id}",method = RequestMethod.GET) @GetMapping("/{id}") public String getById(@PathVariable("id") Integer id){//通过请求路径获取值,而不是通过请求参数 System.out.println("id="+id); return "getById"; } //删除某一个 //@RequestMapping(value = "/{id}",method = RequestMethod.DELETE) @DeleteMapping("/{id}") public String delete(@PathVariable("id") Integer id){ System.out.println("id="+id); return "delete"; } }
@Configuration public class SpringWebSupport extends WebMvcConfigurationSupport { //设置静态资源不走SpringMvc控制器 @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/pages/**").addResourceLocations("/pages/"); registry.addResourceHandler("/css/**").addResourceLocations("/css/"); } }