SpringMVC框架有什么优点?
在Controller中如何定义访问路径,如何响应数据?
1 创建web工程(Maven结构)
2 设置tomcat服务器,加载web工程(tomcat插件)
3 导入坐标(SpringMVC+Servlet)
4 定义处理请求的功能类(UserController)
5 编写SpringMVC配置类,加载处理请求的Bean。
6 加载SpringMVC配置,并设置SpringMVC请求拦截的路径
创建的新工程的话可能得修改下maven(老版创建时就让你设置maven)
或者参考这里设置New Project的默认Maven: 4. new Project 默认maven配置
org.apache.tomcat.maven tomcat7-maven-plugin 2.1 80 /
javax.servlet javax.servlet-api 3.1.0 provided org.springframework spring-webmvc 5.2.10.RELEASE
注意事项:
//定义表现层控制器bean
@Controller
public class UserController {//设置映射路径为/save,即外部访问路径@RequestMapping("/save")//设置当前操作返回结果为指定json数据(本质上是一个字符串信息)@ResponseBody //设置返回值是数据不是页面public String save(){System.out.println("user save ...");return "{'info':'springmvc'}";}
}
注意事项:
对于SpringMVC而言,Controller方法返回值默认表示要跳转的页面,没有对应的页面就会报错。如果不想跳转页面而是响应数据,那么就需要在方法上使用@ResponseBody注解。
//springmvc配置类,本质上还是一个spring配置类
@Configuration
@ComponentScan("com.itheima.controller")
public class SpringMvcConfig {
}
基于web3.0纯注解开发,可以删掉 WEB-INF下的web.xml配置文件
但是就需要ServletContainersInitConfig(名称无所谓) 配置类来加载springmvc了
//web容器配置类
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {//加载springmvc配置类,产生springmvc容器(本质还是spring容器)protected WebApplicationContext createServletApplicationContext() {//初始化WebApplicationContext对象AnnotationConfigWebApplicationContext ioc= new AnnotationConfigWebApplicationContext();//加载指定配置类 【SpringMVC核心配置类】ioc.register(SpringMvcConfig.class);return ioc;}//设置由springmvc控制器处理的请求映射路径protected String[] getServletMappings() {return new String[]{"/"}; //”/“表示 所有的请求 都归SpringMVC管理}//加载spring配置类protected WebApplicationContext createRootApplicationContext() {return null;}
}
@Controller
public class UserController {
}
@RequestMapping("/save")
public void save(){System.out.println("user save ...");
}
注意:其实@RequestMapping注解还可以写到类上面,笔记后面会介绍到。
@RequestMapping("/save")
@ResponseBody
public String save(){System.out.println("user save ...");return "{'info':'springmvc'}";
}
AbstractDispatcherServletInitializer类是SpringMVC提供的快速初始化Web3.0容器的抽象类
AbstractDispatcherServletInitializer提供三个接口方法供用户实现
//加载springmvc配置类,产生springmvc容器(本质还是spring容器)
protected WebApplicationContext createServletApplicationContext() {AnnotationConfigWebApplicationContext ioc= new AnnotationConfigWebApplicationContext(); // 加载容器ioc.register(SpringMvcConfig.class); // springMVC的配置加载到容器中// 上面两行就是加载SpringMVC核心配置文件或类,创建IOC容器//上面2行类似Spring中的这一行: //AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(SpringConfig.class);//也就是说当初写spring时也有这些代码,只不过是写在测试类中的return ioc;
}
//设置由springmvc控制器处理的请求映射路径
protected String[] getServletMappings() {return new String[]{"/"};
}
//加载spring配置类
protected WebApplicationContext createRootApplicationContext() {return null;
}
因为功能不同,如何避免Spring错误的加载到SpringMVC的bean?
spring应该加载管理service和dao的bean
springMVC应该加载管理controller的bean
SpringMVC相关bean(表现层bean)
Spring控制的bean
业务bean(Service)
功能bean(DataSource等)
SpringMVC相关bean加载控制
Spring相关bean加载控制
环境准备:
将上面的入门案例复制一份,稍作修改
pom.xml
4.0.0 cn.whu springmvc_02_bean_load war 1.0-SNAPSHOT javax.servlet javax.servlet-api 3.1.0 provided org.springframework spring-webmvc 5.2.10.RELEASE com.alibaba druid 1.1.16 org.mybatis mybatis 3.5.6 mysql mysql-connector-java 5.1.47 org.springframework spring-jdbc 5.2.10.RELEASE org.mybatis mybatis-spring 1.3.0 org.projectlombok lombok 1.18.26 org.apache.tomcat.maven tomcat7-maven-plugin 2.1 80 /
USE spring_db;
CREATE TABLE tbl_user(id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(255),age INT
);
domain.User
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {private Integer id;private String name;private Integer age;
}
UserDao
public interface UserDao {@Insert("insert into tbl_user(name, age) values(#{name},#{age})")void save(User user);
}
UserService
public interface UserService {public void save(User user);
}
UserServiceImpl
public class UserServiceImpl implements UserService {public void save(User user) {System.out.println("user service ...");}
}
方式1:
@Configuration
@ComponentScan({"cn.whu.service","cn.whu.dao"})
public class SpringConfig {
}
方式2:
@Configuration
@ComponentScan(value = "cn.whu", //我要扫描 cn.whu包下所有BeanexcludeFilters = @ComponentScan.Filter( // 但是我要排除一些type = FilterType.ANNOTATION, // 我要按照注解排除classes = Controller.class // 被 @Controller 注解标注的 我都排除)
)
public class SpringConfig {}
测试的时候需要注掉SpringMvcConfig上的@Configuration或者@ComponentScan(“cn.whu.controller”)任意一个,eg:
因为Spring配置的是cn.whu包下所有,仅仅排除controller, SpringMvcConfig也在cn.whu包下,万一成了配置类,下面的@ComponentScan(“cn.whu.controller”)会工作再次扫描从而又加上了controller。
public class App {public static void main(String[] args) {/*AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext();ioc.register(SpringConfig.class);*/ //两行可以合并为下面一行AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(SpringConfig.class);UserService service = ioc.getBean(UserService.class);System.out.println(service);UserController controller = ioc.getBean(UserController.class);System.out.println(controller);}
}
果然能拿到service但是拿不到controller
方式三:不区分Spring与SpringMVC的环境,加载到同一个环境中
config.ServletContainersInitConfig
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer { // 对应xml开发中: 加载springMVC核心配置文件protected WebApplicationContext createServletApplicationContext() { AnnotationConfigWebApplicationContext ioc= new AnnotationConfigWebApplicationContext();ioc.register(SpringMvcConfig.class);//就是加载核心配置文件或者核心配置类 创建IOC容器return ioc; } // 对应xml开发中: 加载spring核心配置文件protected WebApplicationContext createRootApplicationContext() { // 本来这里只有一行 return null.// 现在这里是Spring环境 上面是SpringMVC环境AnnotationConfigWebApplicationContext ioc= new AnnotationConfigWebApplicationContext(); ioc.register(SpringConfig.class);// 加载spring核心配置 也就是加载spring环境 return ioc; } protected String[] getServletMappings() { return new String[]{"/"}; }
}
简化格式
继承成另一个子抽象类,功能更强大
// 这个类是tomcat自动加载的 应该是按照类型找的吧
// 对应成 web.xml即可 (找实现类)
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {// 对应xml开发: 加载Spring核心配置文件protected Class>[] getRootConfigClasses() {return new Class[]{SpringConfig.class};}// 对应xml开发: 加载SpringMVC核心配置文件protected Class>[] getServletConfigClasses() {return new Class[]{SpringMvcConfig.class};}// 配置SpringMVC拦截所有路径protected String[] getServletMappings() {return new String[]{"/"};}
}
PostMan:邮差
双击资料中的“Postman-win64-8.3.1-Setup.exe”即可自动按照,打开之后需要注册,如果底部有如下链接,可以点击跳过注册
注册一下,好像要科学上网。注册和登录都跳转到浏览器端完成,登录完再切换回桌面程序即可。
点击左上角的home进入主页,然后
注意:第一次请求需要创建一个新的目录,后面就不需要创建新目录,直接保存到已经创建好的目录即可。
环境准备:
创建好缺失的目录结构:
pom.xml
4.0.0 cn.whu springmvc_03_request_mapping war 1.0-SNAPSHOT javax.servlet javax.servlet-api 3.1.0 provided org.springframework spring-webmvc 5.2.10.RELEASE org.apache.tomcat.maven tomcat7-maven-plugin 2.1 80 /
初始代码:
ServletContainersInitConfig
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {// Spring核心配置文件 但是这里用不着Springprotected Class>[] getRootConfigClasses() {return new Class[0];}// SpringMVC核心配置文件(SpringMVC的Controller就是我们的Servlet嘛)protected Class>[] getServletConfigClasses() {return new Class[]{SpringMvcConfig.class};}//配置SpringMVC拦截所有路径protected String[] getServletMappings() {return new String[]{"/"};}
}
SpringMvcConfig
@Configuration
@ComponentScan("cn.whu.controller")
public class SpringMvcConfig {}
BookController
@Controller
public class BookController {@RequestMapping("/save")@ResponseBodypublic String save(){System.out.println("book save ...");return "{'module':'book save'}";}
}
UserController
@Controller
public class UserController {@RequestMapping("/save")@ResponseBodypublic String save(){System.out.println("user save ...");return "{'module':'user save'}";}@RequestMapping("/delete")@ResponseBodypublic String delete(){System.out.println("user delete ...");return "{'module':'user delete'}";}}
很明显,有两个完全相同的"/save"路径,启动服务器报错实属正常
类上面肯定还要@RequestMapping(“/xxx”)来区分下的。看下面吧
@RequestMapping注解注解可以写在哪?有什么作用?
@Controller
//类上方配置的请求映射与方法上面配置的请求映射连接在一起,形成完整的请求映射路径
@RequestMapping("/user")
public class UserController {//请求路径映射@RequestMapping("/save") //此时save方法的访问路径是:/user/save@ResponseBodypublic String save(){System.out.println("user save ...");return "{'module':'user save'}";}
}
PostMan发送请求: (Ctrl+‘+/=’ 可以调大界面字体)
将上面得springmvc_03_request_mapping直接复制一份改名为springmvc_04_request_param,注意pom.xml里也要改:
,然后稍作修改
(红框框出来的都是有修改的)
@Controller
// 只有一个Controller就先不写前缀啦
public class UserController {@RequestMapping("/commonParam")@ResponseBodypublic String commonParam(){return "{'module':'common param'}";}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Address {private String province;private String city;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {private String name;private int age;private Address address;
}
如何解决POST请求中文乱码问题?
普通参数直接写在方法的形参里即可获取,类型写自己想要的类型,springMVC会自动帮你进行String->其他各种类型的转换
//普通参数:请求参数与形参名称对应即可完成参数传递
@RequestMapping("/commonParam")
@ResponseBody
public String commonParam(String name,Integer age){//直接写在参数里,即可接收浏览器发送的参数System.out.println(name);System.out.println(age+" "+age.getClass());//甚至类型转换都帮你自动弄好了return "{'module':'common param'}";
}
org.apache.tomcat.maven tomcat7-maven-plugin 2.1 80 / UTF-8
后台代码没有任何变化
//普通参数:请求参数与形参名称对应即可完成参数传递
@RequestMapping("/commonParam")
@ResponseBody
public String commonParam(String name,Integer age){//直接写在参数里,即可接收浏览器发送的参数System.out.println(name);System.out.println(age+" "+age.getClass());//甚至类型转换都帮你自动弄好了return "{'module':'common param'}";
}
问题:我们发现,POST请求传递的参数如果包含中文那么就会出现中文乱码问题,说明我们之前配置的tomcat插件uri路径编解码字符集无法解决POST请求中文乱码问题。那么如何解决呢?
在加载SpringMVC配置的配置类中指定字符过滤器。
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {protected Class>[] getRootConfigClasses() {return new Class[0];}protected Class>[] getServletConfigClasses() {return new Class[]{SpringMvcConfig.class};}protected String[] getServletMappings() {return new String[]{"/"};}//Post请求乱码处理@Override //本质也是过滤器 (这里写新的方法,就相当于xml中写新的配置)protected Filter[] getServletFilters() {//可以自己写过滤器Filter,但是SpringMVC肯定有内置写好的CharacterEncodingFilter filter = new CharacterEncodingFilter();filter.setEncoding("utf-8");return new Filter[]{filter};}
}
当请求参数名与形参变量名不同,该如何接收请求参数?
//普通参数:请求参数名与形参名不同时,
@RequestMapping("/commonParamDifferentName")
@ResponseBody
public String commonParamDifferentName(String userName, int age){System.out.println("普通参数传递 userName => "+ userName);System.out.println("普通参数传递 age => "+age);return "{'module':'common param different name'}";
}
使用@RequestParam注解关联请求参数名称与形参名称之间的关系
// 普通参数:请求参数名与形参名不同时,使用@RequestParam注解关联请求参数名称与形参名称之间的关系@RequestMapping("/commonParamDifferentName")@ResponseBodypublic String commonParamDifferentName(@RequestParam("name") String userName, int age){System.out.println("普通参数传递 userName => "+ userName);System.out.println("普通参数传递 age => "+age);return "{'module':'common param different name'}";}
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {private String name;private int age;private Address address;
}
//POJO参数:请求参数与形参对象中的属性对应即可完成参数传递
@RequestMapping("/pojoParam")
@ResponseBody
public String pojoParam(User user){System.out.println("pojo参数传递: user => "+user);return "{'module':'pojo param'}";
}
注意事项:请求参数key的名称要和POJO中属性的名称一致,否则无法封装。
@Data
@ToString
public class User {private String name;private int age;private Address address;
}@Data
@ToString
public class Address {private String province;private String city;
}
//嵌套POJO参数:嵌套属性按照层次结构设定名称即可完成参数传递
@RequestMapping("/pojoContainPojoParam")
@ResponseBody
public String pojoContainPojoParam(User user){System.out.println("pojo嵌套pojo参数传递: "+user);return "{'module':'pojo contain pojo param'}";
}
注意事项:请求参数key的名称要和POJO中属性的名称一致,否则无法封装。
//数组参数:同名请求参数可以直接映射到对应名称的形参数组对象中
// 很简单: 写个对应名称的数组参数即可
@RequestMapping("/arraysParam")
@ResponseBody
public String arraysParam(String[] hobbies){System.out.println(Arrays.toString(hobbies));return "{'module':'arrays Param'}";
}
相同的名称以数组格式传递参数(不就是复选框嘛)
//集合参数:同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据
@RequestMapping("/listParam")
@ResponseBody
public String listParam(@RequestParam List hobbies){System.out.println("集合参数传递:" + hobbies);return "{'module':'list Param'}";
}
注意必须在参数前写@RequestParam,否则一发现List是引用类型,框架会调用构造方法先创建对象,然后将参数都当做其属性set进去,也就是所有的引用类型默认按照pojo类型去干。很明显List参数不是这个意思
加上@RequestParam,就是告诉框架,参数一个个给我放到集合中就行了
正常名称对名称就OK了,名称对不上咋办?@RequestParam 绑定关系
问题:@EnableWebMvc注解和@ResponseBody注解有什么用?
com.fasterxml.jackson.core jackson-databind 2.9.0
看名字就知道:json数据绑定。自动帮你调用fastjson,将json自动转换为pojo
SpringMvcConfig 核心配置文件里加一行注解@EnableWebMvc
SpringMVC就会将前端传送过来的json自动转换成对应的类型了
tip: @EnableWebMvc 功能强大,远不止封装json这一个
@Configuration
@ComponentScan("cn.whu.controller")
//开启json数据类型自动转换
@EnableWebMvc
public class SpringMvcConfig {
}
注意事项:
@EnableWebMvc注解功能强大,该注解整合了多个功能,此处仅使用其中一部分功能,即json数据进行自动类型转换
//集合参数:json格式
//1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc
//2.使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据@RequestMapping("/listParamForJson")@ResponseBody //注意@RequestParam不行了,json数据在请求体中,得用@RequestBodypublic String listParamForJson(@RequestBody List hobbies){System.out.println("list集合 json 参数传递:" +hobbies);return "{'module':'list common for json Param'}";}
@Configuration
@ComponentScan("cn.whu.controller")
@EnableWebMvc
public class SpringMvcConfig {
}
@RequestMapping("/listParamForJson")
@ResponseBody
public String listParamForJson(@RequestBody List likes){System.out.println("list common(json)参数传递 list ==> "+likes);return "{'module':'list common for json param'}";
}
参数前还是得加@RequestBody 不然封装不上(没办法,json都在请求体中, 必须都注明一下)
//POJO参数:json格式
//1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc
//2.使用@RequestBody注解将外部传递的json数据映射到形参的实体类对象中,要求属性名称一一对应
//POJO参数: json格式
@RequestMapping("/pojoParamForJson")
@ResponseBody
public String pojoParamForJson(@RequestBody User user){//@RequestBody 还是得加System.out.println("pojo json 参数传递: user => "+user);return "{'module':'pojo json param'}";
}
不妨把address也加上,反正,json简单
//集合参数:json格式
//1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc
//2.使用@RequestBody注解将外部传递的json数组数据映射到形参的保存实体类对象的集合对象中,要求属性名称一一对应
//集合参数: json格式 元素为pojo
@RequestMapping("/listPojoParamForJson")
@ResponseBody
public String listPojoParamForJson(@RequestBody List list){System.out.println("pojo集合-json参数:" +list);return "{'module':'list pojo json Param'}";
}
写多了就简单了,就是直接写类型,然后json格式要多加个注解@RequestBody (配置文件里先开注解)
@DateTimeFormat注解的作用是什么?
//日期参数 http://localhost:80/dataParam?date=2088/08/08&date1=2088-08-18&date2=2088/08/28 8:08:08
//使用@DateTimeFormat注解设置日期类型数据格式,默认格式yyyy/MM/dd
@RequestMapping("/dataParam")
@ResponseBody
public String dataParam(Date date,@DateTimeFormat(pattern = "yyyy-MM-dd") Date date1,@DateTimeFormat(pattern = "yyyy/MM/dd HH:mm:ss") Date date2){System.out.println("日期参数传递 date: "+date);System.out.println("日期参数传递 date1 (yyyy-MM-dd): "+date1);System.out.println("日期参数传递 date2 (yyyy/MM/dd HH:mm:ss): "+date2);return "{'module':'data Param'}";
}
名称:@DateTimeFormat
类型:形参注解
位置:SpringMVC控制器方法形参前面
作用:设定日期时间型数据格式
属性:pattern:指定日期时间格式字符串
public interface Converter {@NullableT convert(S var1);
}
传递日期类型参数必须在配置类上使用@EnableWebMvc注解。其功能之一:根据类型匹配对应的类型转换器。
注意:需要添加jackson-databind依赖以及在SpringMvcConfig配置类上添加@EnableWebMvc注解
如何响应json数据?
新环境了,将上面的springmvc_04_request_param复制一份改名springmvc_05_response
删掉domain下的Address,只留下User就行了
index.jsp改成page.jsp
Hello Spring MVC!
然后UserController里处理器方法全部删掉,待会儿写全新的
@Controller
public class UserController {//响应页面/跳转页面//返回值为String类型,设置返回值为页面名称,即可实现页面跳转@RequestMapping("/toJumpPage")public String toJumpPage(){System.out.println("跳转页面");return "page.jsp";}
}
//响应文本数据
//返回值为String类型,设置返回值为任意字符串信息,即可实现返回指定字符串信息,需要依赖@ResponseBody注解
@RequestMapping("/toText")
@ResponseBody
public String toTest(){System.out.println("返回(响应)纯文本数据");return "response text";
}
@ResponseBody注解后,直接返回User对象即可。(牛)
//响应POJO对象
//返回值为实体类对象,设置返回值为实体类类型,即可实现返回对应对象的json数据,需要依赖@ResponseBody注解和@EnableWebMvc注解
@RequestMapping("/toJsonPOJO")
@ResponseBody //返回数据不是页面
public User toJsonPOJO(){User user = new User();user.setName("whu");user.setAge(130);return user; //直接返回pojo即可 自动转json串给前端
}
POJO转json不算SpringMVC做的,而是jackson-databind做的
没什么特别的 直接返回即可 (注解还是@ResponseBody)
//响应POJO集合对象
//返回值为集合对象,设置返回值为集合类型,即可实现返回对应集合的json数组数据,需要依赖@ResponseBody注解和@EnableWebMvc注解
@RequestMapping("/toJsonList")
@ResponseBody
public List toJsonList(){System.out.println("返回json集合数据");User user1 = new User();user1.setName("传智播客");user1.setAge(15);User user2 = new User();user2.setName("黑马程序员");user2.setAge(12);List userList = new ArrayList();userList.add(user1);userList.add(user2);return userList;
}
注意:需要添加jackson-databind依赖以及在SpringMvcConfig配置类上添加@EnableWebMvc注解
Rest风格使用了几种请求方式定义访问行为?
请求Method不止有GET和POST,还有好多,这里出现了另外两个常用的:PUT、DELETE
SpringMVC共支持8种提交方式:
Rest风格如何通过路径传递参数?
上面的module:springmvc_05_response复制一份为springmvc_06_rest
其中 Book
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Book {private String name;private double price;
}
UserController 初始为这样:也就是非RESTful风格
@Controller
public class UserController {@RequestMapping("/save")@ResponseBodypublic String save(@RequestBody User user) {System.out.println("user save... " + user);return "{'module':'user save'}";}@RequestMapping("/delete")@ResponseBodypublic String delete(Integer id) {System.out.println("user delete... " + id);return "{'module':'user update'}";}@RequestMapping("/update")@ResponseBodypublic String update(@RequestBody User user) {System.out.println("user update... " + user);return "{'module':'user update'}";}@RequestMapping("/getById")@ResponseBodypublic String getById(Integer id) {System.out.println("user getById... " + id);return "{'module':'user update'}";}@RequestMapping("/getAll")@ResponseBodypublic String getAll(){System.out.println("user getAll...");return "{'module':'user getAll'}";}}
下面的学习任务就是将上面那些方法改成RESTful风格
做法:在Controller中定义方法时设定"http请求动作(请求方式)“和"设定请求参数(路径变量)”
@Controller
public class UserController {//设置当前请求方法为POST,表示REST风格中的添加操作@RequestMapping(value = "/users",method = RequestMethod.POST)@ResponseBodypublic String save(){System.out.println("user save...");return "{'module':'user save'}";}//设置当前请求方法为DELETE,表示REST风格中的删除操作//@PathVariable注解用于设置路径变量(路径参数),要求路径上设置对应的占位符,并且占位符名称与方法形参名称相同@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)@ResponseBodypublic String delete(@PathVariable Integer id){System.out.println("user delete..." + id);return "{'module':'user delete'}";}//设置当前请求方法为PUT,表示REST风格中的修改操作@RequestMapping(value = "/users",method = RequestMethod.PUT)@ResponseBodypublic String update(@RequestBody User user){System.out.println("user update..."+user);return "{'module':'user update'}";}//设置当前请求方法为GET,表示REST风格中的查询操作//@PathVariable注解用于设置路径变量(路径参数),要求路径上设置对应的占位符,并且占位符名称与方法形参名称相同@RequestMapping(value = "/users/{id}" ,method = RequestMethod.GET)@ResponseBodypublic String getById(@PathVariable Integer id){System.out.println("user getById..."+id);return "{'module':'user getById'}";}//设置当前请求方法为GET,表示REST风格中的查询操作@RequestMapping(value = "/users",method = RequestMethod.GET)@ResponseBodypublic String getAll(){System.out.println("user getAll...");return "{'module':'user getAll'}";}
}
save
//设置当前请求方法为POST,表示REST风格中的添加操作
@RequestMapping(value = "/users",method = RequestMethod.POST)
@ResponseBody
public String save(){System.out.println("user save...");return "{'module':'user save'}";
}
delete
//设置当前请求方法为DELETE,表示REST风格中的删除操作
//@PathVariable注解用于设置路径变量(路径参数),要求路径上设置对应的占位符,并且占位符名称与方法形参名称相同
@RequestMapping(value = "/users/{id}", method = RequestMethod.DELETE)
@ResponseBody // 路径变量 二者得配合着用
public String delete(@PathVariable Integer id) { // /users/1的形式给出id值System.out.println("user delete... " + id);return "{'module':'user delete'}";
}
update
//设置当前请求方法为PUT,表示REST风格中的修改操作@RequestMapping(value = "/users",method = RequestMethod.PUT)@ResponseBodypublic String update(@RequestBody User user){System.out.println("user update..."+user);return "{'module':'user update'}";}
getById
//设置当前请求方法为GET,表示REST风格中的查询操作//@PathVariable注解用于设置路径变量(路径参数),要求路径上设置对应的占位符,并且占位符名称与方法形参名称相同@RequestMapping(value = "/users/{id}" ,method = RequestMethod.GET)@ResponseBodypublic String getById(@PathVariable Integer id){System.out.println("user getById..."+id);return "{'module':'user getById'}";}
getAll
//设置当前请求方法为GET,表示REST风格中的查询操作
@RequestMapping(value = "/users",method = RequestMethod.GET)
@ResponseBody
public String getAll(){System.out.println("user getAll...");return "{'module':'user getAll'}";
}
还是上面那个module,不过这次在BookController里面写了
BookController 初始这样 (学习任务就是在此基础上进行简化)
@Controller
public class BookController {@RequestMapping(value = "/books",method = RequestMethod.POST)@ResponseBodypublic String save(@RequestBody Book book){System.out.println("book save ... " + book);return "{'module':'book save'}";}@RequestMapping(value = "/books/{id}",method = RequestMethod.DELETE)@ResponseBodypublic String delete(@PathVariable Integer id){System.out.println("book deleteById, id = " + id);return "{'module':'book delete'}";}@RequestMapping(value = "/books",method = RequestMethod.PUT)@ResponseBodypublic String update(@RequestBody Book book){System.out.println("book update ... " + book);return "{'module':'book update'}";}@RequestMapping(value = "/books/{id}",method = RequestMethod.GET)@ResponseBodypublic String getById(@PathVariable Integer id){System.out.println("book getById id = "+ id);return "{'module':'book getById'}";}@RequestMapping(value = "/books",method = RequestMethod.GET)@ResponseBodypublic String getAll(){System.out.println("book getAll ");return "{'module':'book getAll'}";}
}
以上截图中的代码和我们之前写的UserController中的方法类似,其中图中两个方法都有三处是有问题的,可以进行优化。存在的问题如下:
问题1:每个方法的@RequestMapping注解中都定义了访问路径/books,重复性太高。
问题2:每个方法的@RequestMapping注解中都要使用method属性定义请求方式,重复性太高。
问题3:每个方法响应json都需要加上@ResponseBody注解,重复性太高。
解决以上三个问题
解决问题1:在Controller类上使用@RequestMapping定义共同的访问路径。
类上写注解
@RequestMapping("/books")
下面所有的value="/books"
value属性都可以省略了
但是value="/books/{id}"
还得写成value="/{id}"
value属性暂时省不掉
@Controller
@RequestMapping("/books")
public class BookController1 {@RequestMapping(method = RequestMethod.POST)@ResponseBodypublic String save(@RequestBody Book book){System.out.println("book save ... " + book);return "{'module':'book save'}";}@RequestMapping(value = "/{id}",method = RequestMethod.DELETE)@ResponseBodypublic String delete(@PathVariable Integer id){System.out.println("book deleteById, id = " + id);return "{'module':'book delete'}";}@RequestMapping(method = RequestMethod.PUT)@ResponseBodypublic String update(@RequestBody Book book){System.out.println("book update ... " + book);return "{'module':'book update'}";}@RequestMapping(value = "/{id}",method = RequestMethod.GET)@ResponseBodypublic String getById(@PathVariable Integer id){System.out.println("book getById id = "+ id);return "{'module':'book getById'}";}@RequestMapping(method = RequestMethod.GET)@ResponseBodypublic String getAll(){System.out.println("book getAll ");return "{'module':'book getAll'}";}
}
解决问题2:每个方法都有@ResponseBody
,直接写到类上,然后合二为一: @RestController
@ResponseBody
每个都有,直接写类上,下面方法就都不用写了
这样类上面有了两个注解@Controller
和@ResponseBody
,他们两又可以合二为一:@RestController
简言之:@RestController
=@Controller
+@ResponseBody
+ “一些无关紧要的”
@RestController
@RequestMapping("/books")
public class BookController {@RequestMapping(method = RequestMethod.POST)public String save(@RequestBody Book book){System.out.println("book save ... " + book);return "{'module':'book save'}";}@RequestMapping(value = "/{id}",method = RequestMethod.DELETE)public String delete(@PathVariable Integer id){System.out.println("book deleteById, id = " + id);return "{'module':'book delete'}";}@RequestMapping(method = RequestMethod.PUT)public String update(@RequestBody Book book){System.out.println("book update ... " + book);return "{'module':'book update'}";}@RequestMapping(value = "/{id}",method = RequestMethod.GET)public String getById(@PathVariable Integer id){System.out.println("book getById id = "+ id);return "{'module':'book getById'}";}@RequestMapping(method = RequestMethod.GET)public String getAll(){System.out.println("book getAll ");return "{'module':'book getAll'}";}
}
解决问题3:使用@GetMapping @PostMapping @PutMapping @DeleteMapping代替@RequestMapping(method=RequestMethod.XXX)
@RestController
@RequestMapping("/books")
public class BookController4 {//@RequestMapping(method = RequestMethod.POST)@PostMapping //和上面写法等价 [使用@PostMapping简化Post请求方法对应的映射配置]public String save(@RequestBody Book book){System.out.println("book save ... " + book);return "{'module':'book save'}";}//@RequestMapping(value = "/{id}",method = RequestMethod.DELETE)@DeleteMapping("/{id}")public String delete(@PathVariable Integer id){System.out.println("book deleteById, id = " + id);return "{'module':'book delete'}";}//@RequestMapping(method = RequestMethod.PUT)@PutMappingpublic String update(@RequestBody Book book){System.out.println("book update ... " + book);return "{'module':'book update'}";}//@RequestMapping(value = "/{id}",method = RequestMethod.GET)@GetMapping("/{id}")public String getById(@PathVariable Integer id){System.out.println("book getById id = "+ id);return "{'module':'book getById'}";}//@RequestMapping(method = RequestMethod.GET)@GetMappingpublic String getAll(){System.out.println("book getAll ");return "{'module':'book getAll'}";}
}
重新一一访问:
都能正常访问,真不错
(重复了 但是舍不得删)
注:在Controller类上使用@RestController注解,等同于@Controller与@ResponseBody两个注解组合功能
@RestController //使用@RestController注解替换@Controller与@ResponseBody注解,简化书写
@RequestMapping("/books")
public class BookController {//方法省略了没写
}
//TODO
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-waoc1XVG-1679489526804)(assets/image-20210805140535262.png)]
//POJO实体类
public class Book {private Integer id;private String type;private String name;private String description;//同学们自己重写getter、setter、toString()方法...
}//SpringMVC容器初始化类
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {protected Class>[] getRootConfigClasses() {return new Class[0];}protected Class>[] getServletConfigClasses() {return new Class[]{SpringMvcConfig.class};}protected String[] getServletMappings() {return new String[]{"/"};}//乱码处理@Overrideprotected Filter[] getServletFilters() {CharacterEncodingFilter filter = new CharacterEncodingFilter();filter.setEncoding("UTF-8");return new Filter[]{filter};}
}//SpringMVC配置类
@Configuration
@ComponentScan({"com.itheima.controller","com.itheima.config"})
@EnableWebMvc
public class SpringMvcConfig {
}
@RestController
@RequestMapping("/books")
public class BookController {@PostMappingpublic String save(@RequestBody Book book){System.out.println("book save ==> "+ book);return "{'module':'book save success'}";}@GetMappingpublic List getAll(){System.out.println("book getAll is running ...");List bookList = new ArrayList();Book book1 = new Book();book1.setType("计算机");book1.setName("SpringMVC入门教程");book1.setDescription("小试牛刀");bookList.add(book1);Book book2 = new Book();book2.setType("计算机");book2.setName("SpringMVC实战教程");book2.setDescription("一代宗师");bookList.add(book2);Book book3 = new Book();book3.setType("计算机丛书");book3.setName("SpringMVC实战教程进阶");book3.setDescription("一代宗师呕心创作");bookList.add(book3);return bookList;}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H0MNxmTP-1679489526804)(assets/image-20210805140307371.png)]
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {//设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {//当访问/pages/????时候,从/pages目录下查找内容registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");registry.addResourceHandler("/js/**").addResourceLocations("/js/"); registry.addResourceHandler("/css/**").addResourceLocations("/css/"); registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");}
}
//添加
saveBook () {axios.post("/books",this.formData).then((res)=>{});
},
//主页列表查询
getAll() {axios.get("/books").then((res)=>{this.dataList = res.data;});
},