学习流程图:
四个学习模块:
1、SpringMVC入门
2、请求与响应
3、rest风格
4、ssm整合
5、拦截器
第一章、SpringMVC入门
1、简介
SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架。
SpringMVC的开发步骤:
① 导入SpringMVC相关坐标
② 配置SpringMVC核心控制器DispathcerServlet
③ 创建Controller类和视图页面
④ 使用注解配置Controller类中业务方法的映射地址
⑤ 配置SpringMVC核心文件 spring-mvc.xml
⑥ 客户端发起请求测试
2、SpringMVC入门案例
1、导入servlet-api与spring-webmvc依赖坐标
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.1.RELEASE</version></dependency>
2、创建SpringMVC控制器类(等同于Servlet接受请求与响应)
@Controller //定义spring的bean
public class UserController {@RequestMapping("/save")// 设置当前操作的访问URL路径@ResponseBody //设置以下的方法是执行响应的方法
// 定义具体的处理请求操作,向外返回JSON数据public String save(){System.out.println("此处是处理请求的方法");return "{'module':'springmvc'}";}
}
3、创建spring配置类,扫描bean
//创建spring配置类,扫描controller对应的bean
@Configuration
@ComponentScan("com.itheima.controller")
public class SpringmvcConfig {
}
4、初始化Servlet容器,加载配置类,设置请求方法
创建一个web容器并加载spring配置类完成注册;设置请求映射路径,直接”/“表示全部
//定义一个Servlet容器启动的配置类,在里面加载spring的配置
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
//让Tomcat能够加载SpringMVC容器的配置@Overrideprotected WebApplicationContext createServletApplicationContext() {AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();ctx.register(SpringmvcConfig.class);return ctx;}
//设置哪些请求归属SpringMVC处理@Overrideprotected String[] getServletMappings() {return new String[]{"/"};//设置所有请求归属SpringMVC处理}@Override //加载spring配置类的protected WebApplicationContext createRootApplicationContext() {return null;}
}
三个实现方法详解:
5、总结:
<基本目录>
<常用注解>
@Controller //类注解:将该类定义为spring的bean;
@RequestMapping("/save")// 方法注解:写在方法上面,设置当前方法的访问URL路径, 可类比 Servlet开发中web.xml配置的servlet-mapping标签作用;
@ResponseBody //方法注解:设置以下的方法的返回值作为响应体数据反馈给浏览器;
3、SpringMVC工作流程分析
《1》容器初始化 (ServletContext对象看做Web程序实例化对象)
《2》单次请求
4、controller加载控制
SpringmvcConfig配置类和SpringConfig配置类功能一样,就是扫描bean,只是扫描的范围不同。但是存在着重复扫描加载,那bean就不晓得听谁话了!
《1》问题:
《2》解决方案:
方案二中SpringConfig配置类
@Configuration
//@ComponentScan({"com.itheima.dao","com.itheima.service"})//设定精确包扫描范围
@ComponentScan(value = "com.itheima",excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)
)
//解释:我去扫描包com.itheima里面的所有的包,设置过滤器,按照注解排除,排除掉指定classes的包public class SpringConfig {}
SpringMvcConfig配置类
@Configuration
@ComponentScan("com.itheima.controller")
public class SpringMvcConfig {
}
Servlet容器配置类 ServletContainersInitConfig :加载Spring与SpringMVC容器
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {// springMVC容器加载配置@Overrideprotected WebApplicationContext createServletApplicationContext() {AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();ctx.register(SpringMvcConfig.class);return ctx;}
// Spring容器加载配置@Overrideprotected WebApplicationContext createRootApplicationContext() {AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();ctx.register(SpringConfig.class);return ctx;}@Overrideprotected String[] getServletMappings() {return new String[]{"/"};}
}
5、PostMan
网页调试与发送http请求的插件。
作用:常用于接口测试。
第二章、请求与响应
1、请求映射路径
在类上统一设置当前控制器方法请求访问路径前缀。
@Controller
@RequestMapping("/user") //访问路径前缀 ,目的是区别不同的controller类
public class UserController {@RequestMapping("/save") //具体的方法的请求路径@ResponseBodypublic String save(){System.out.println("此处是usercontroller类中的save方法");return "{'我要吃饭了':'真的好饿'}";}@RequestMapping("/delete")@ResponseBodypublic String delete(){System.out.println("此处是us二controller内的delete方法");return "{'我真的要饿死了':'一点也不好玩'";}}
2、请求参数
直接在方法内写入形式参数即可。在发出请求的时候输入参数就会传入。
《1、普通参数》
请求url(?表示接下来的是参数 使用&分隔不同的参数)
http://localhost:8080/springMVC_02_bean_load_war/commonParam?name=我是你爹 & age=100
方法写入形参
URL中参数名与方法内的形参名会自动映射,相同则直接传参。 如果不匹配使用@RequestParam(”里面写上前端的对应的名称“)
@RequestMapping("/commonParam")@ResponseBodypublic String commonParam(String name,int age,String text){System.out.println("接收到的普通参数name是:=============》" + name);System.out.println("接收到的普通参数age是:=============》" + age);System.out.println("接收到的普通参数text是:=============》" + text);return "{'module':'commonParam'}";}
post请求参数乱码处理
在 Web容器配置类ServletContainersInitConfig类中使用过滤器处理
//乱码处理 重写getServletFilters()方法@Overrideprotected Filter[] getServletFilters() {CharacterEncodingFilter filter = new CharacterEncodingFilter();filter.setEncoding("UTF-8");return new Filter[] {filter};}
post请求方法----参数在请求体
《2、POJO参数》
实际开发中,是接收大量参数组成一个实体类
定义一个实体类,声明属性、toString()以及setter()&getter()
将此实体类对象作为方法内的 形参
//POJO参数@RequestMapping("/pojoParam")@ResponseBodypublic String pojoParam(User user){System.out.println("pojo参数传递user --》" + user);return "{'module':'pojo param'}";}
基于本框架,前端页面传的所有参数属性,会自动根据名称和实体类的属性匹配、赋值。
《3、POJO嵌套》
对应引用类型传参,正常在后端就正常定义实体类就行了。
但在前端传参的时候,aa.bb 前者是引用对象实例,后者是传参属性
《4、数组参数》
对于数组参数,只需要在前端传参时将名称全部写为数组名即可。
//数组参数@RequestMapping("/arrayParam")@ResponseBodypublic String arrayParam(String[] arr){System.out.println("数组参数传递为:" + Arrays.toString(arr));return "{'module':'arrayparam'";}
《5、集合参数》
//集合参数@RequestMapping("/listParam")@ResponseBodypublic String listParam(@RequestParam List<String> likes){System.out.println("数组参数传递为:" + likes);return "{'module':'arrayparam'";}
3、日期类型参数传递
4、JSON数据传参
基本四步骤:
1、添加依赖坐标 --> 2、SpringMVC配置类添加注解 --> 3、注意前端传参改为JSON数据 --> 4、方法内形参前添加注解 @RequestBody(接收json数据)
在SpringMVC配置类SpringMvcConfig中添加注解 实现前端JSON数据可以转化为被后端接收的数据
@EnableWebMvc //开启由JSON数据转换为List集合数据
《1、集合参数:json格式》
//集合参数 JSON数据格式@RequestMapping("/listParamForJson")@ResponseBody //由于传过来的JSON数据在请求体内,所以参数要使用RequestBody注解public String listParamForJson(@RequestBody List<String> likes){System.out.println("数组参数传递为:" + likes);return "{'module':'list common for json param'}";}
《2、pojo参数:json格式》
//pojo参数:json格式@RequestMapping("/pojoParamForJson")@ResponseBody //由于传过来的JSON数据在请求体内,所以参数要使用RequestBody注解-把请求体内的json数据塞到参数中public String pojoParamForJson(@RequestBody User user){System.out.println("数组参数传递为:" + user);return "{'module':'list common for json param'}";}
《3、集合对象参数:json格式》
//集合pojo参数:json格式@RequestMapping("/listpojoParamForJson")@ResponseBody //由于传过来的JSON数据在请求体内,所以参数要使用RequestBody注解-把请求体内的json数据塞到参数中public String listpojoParamForJson(@RequestBody List<User> list){System.out.println("数组参数传递为:" + list);return "{'module':'list common for json param'}";}
5、响应
@ResponseBody 作用:设置当前控制器返回值为响应体
响应页面--返回页面文件名
//响应页面、跳转页面@RequestMapping("/toJumpPage")public String toJumpPage(){System.out.println("成功跳转页面");return "page.jsp";}
响应数据--文本数据
文本数据要放在响应体内!!!使用 @ResponseBody 标明!!!1
// 响应文本数据@RequestMapping("/toText")@ResponseBodypublic String toText(){System.out.println("响应返回文本数据");return "Response text";}
响应数据--json数据
json数据要放在响应体内
// 响应pojo对象@RequestMapping("toJsonPOJO")@ResponseBodypublic User toJsonPOJO(){System.out.println("响应返回json对象数据");User user = new User();user.setName("我是你大爷的太祖宗");user.setAge(100);return user;}// 响应pojo对象@RequestMapping("toJsonlistPOJO")@ResponseBodypublic List<User> toJsonlistPOJO(){System.out.println("响应返回json对象数据");User user1 = new User();user1.setName("我是你大爷的太太太太太太祖宗");user1.setAge(100);User user2 = new User();user2.setName("我是你大爷的怎嫩嗯嗯嗯嗯嗯嗯嗯嗯祖宗");user2.setAge(500);User user3 = new User();user3.setName("我是你大爷的顺丰到付大幅度太祖宗");user3.setAge(1000);List<User> users = new ArrayList<>();users.add(user1);users.add(user2);users.add(user3);return users;}
HttpMessageConverter接口:将文本类型、集合等数据转换为json数据类型
第三章、REST风格
1、REST简介
REST见文知意,他的目的就是程序员约定俗成的”规范“。也就是主流的代码风格。
《1》REST风格就是描述资源的访问形式
《2》REST 内部通过访问资源时 行为方式 区分资源操作方式。
资源操作方式=资源路径 + 请求方式。
在实际开发中,@RequestMapping 的路径要改为类名 ;并且指定访问方法
@RequestMapping(value = "/users",method = RequestMethod.POST) //具体的方法的请求路径@ResponseBodypublic String save(){System.out.println("此处是usercontroller类中的save方法");return "{'我要吃饭了':'真的好饿'}";}
传参:
value要指定参数路径位置/路径/{参数名};形参要添加@PathVariable 表示参数从路径中得到
@RequestMapping(value = "/users",method = RequestMethod.POST) //具体的方法的请求路径@ResponseBodypublic String save(){System.out.println("此处是usercontroller类中的save方法");return "{'我要吃饭了':'真的好饿'}";}@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)@ResponseBodypublic String delete(@PathVariable Integer id){System.out.println("此处是us二controller内的delete方法" + id);return "{'我真的要饿死了':'一点也不好玩'";}@RequestMapping(value = "/users",method = RequestMethod.PUT)@ResponseBodypublic String update(@RequestBody User user){System.out.println("此处是us二controller内的update方法" + user);return "{'module':'erertrgtrt'}";}
以后开发中,基本上都是将数据封装成pojo,然后通过json串传递。
2、RESTful入门案例
@RequestMapping(value = "/users",method = RequestMethod.POST) //具体的方法的请求路径@ResponseBodypublic String save(){System.out.println("此处是usercontroller类中的save方法");return "{'我要吃饭了':'真的好饿'}";}@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)@ResponseBodypublic String delete(@PathVariable Integer id){System.out.println("此处是us二controller内的delete方法" + id);return "{'我真的要饿死了':'一点也不好玩'";}@RequestMapping(value = "/users",method = RequestMethod.PUT)@ResponseBodypublic String update(@RequestBody User user){System.out.println("此处是us二controller内的update方法" + user);return "{'module':'erertrgtrt'}";}
3、REST快速开发(简化代码)
对于相同的注解、mapping,直接在类前面写。
@RestController = @Controller + @ResponseBody
对于映射直接写请求方法+mapping,需要单独添加参数后面加。
@RestController
@RequestMapping("/books")
public class BookController {@PostMappingpublic String save(@RequestBody Book book) {System.out.println("此处是控制层save方法");return "{'module':'你爹爹的}";}@DeleteMapping("/{id}")public String delete(@PathVariable Integer id) {System.out.println("此处是delete方法接收到id为" + id);return "{'module':'你爹爹的}";}@PutMappingpublic String update(@RequestBody Book book) {System.out.println("此处是控制层update方法更新的数据为" + book );return "{'module':'update'}";}@GetMapping("/{id}")public String getById(@PathVariable Integer id) {System.out.println("此处是控制层得到的id的数据为" + id );return "{'module':'getbyid'}";}
4、案例:基于RESTful页面数据交互
实现功能:前端页面的数据可以提交到后台,后台的数据可以传到前台显示。
对于css、pages、js等静态资源,应当是由Tomcat服务器直接传送,而不要被SpringMVC拦截,所以要单独设置配置类一旦扫描到指定的资源就放行。
没有解决SpringMVC拦截静态资源 API都是原样子写的咋就不行了呢》?》
第四章、SSM整合
1、SSM整合
企业开发停下来做测试:
业务层写完进行junit测试;控制层写完使用postman进行测试前后端数据交互。
配置事务三部曲:
1、开启注解式事务驱动
在SpringConfig配置类中添加 @EnableTransactionManagement
2、配置事务管理器
在jdbcConfig配置类中
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){DataSourceTransactionManager ds = new DataSourceTransactionManager();ds.setDataSource(dataSource);return ds;}
3、配置事务,把事务配到接口上
业务层接口内上方添加 @Transactional
2、表现层数据封装
返回数据,可能是空、报错、返回数据、返回消息等多种数据格式。
于是数据封装成统一格式。包含三个信息:code、data、msg。
根据code判断返回结果的 请求方法以及正误;
根据code是否进行获取data以及msg。
创建含有不同属性的构造方法,针对不同请求方法返回不同结果
public Result() {}public Result(Integer code,Object data) {this.data = data;this.code = code;}public Result(Integer code,Object data, String msg) {this.data = data;this.code = code;this.msg = msg;}
创建状态码类,以便针对前端确认 请求方法及正误
public class Code {public static final Integer SAVE_OK = 20011;public static final Integer DELETE_OK = 20021;public static final Integer UPDATE_OK = 20031;public static final Integer GET_OK = 20041;public static final Integer SAVE_ERR = 20010;public static final Integer DELETE_ERR = 20020;public static final Integer UPDATE_ERR = 20030;public static final Integer GET_ERR = 20040;}
返回结果实例:(get id= 11)
将最终返回结果都封装成指定的格式
public Result save(@RequestBody Book book) {boolean flag = bookService.save(book);return new Result(flag ? Code.SAVE_OK : Code.SAVE_ERR,flag);}@PutMappingpublic Result update(@RequestBody Book book) {boolean flag = bookService.update(book);return new Result(flag ? Code.UPDATE_OK : Code.UPDATE_ERR,flag);}@DeleteMapping("/{id}")public Result delete(@PathVariable Integer id) {boolean flag = bookService.delete(id);return new Result(flag ? Code.DELETE_OK : Code.DELETE_ERR,flag);}@GetMapping("/{id}")public Result getById(@PathVariable Integer id) {Book book = bookService.getById(id);Integer code = book != null ? Code.GET_OK : Code.GET_ERR;String msg = book != null ? "" : "数据查询失败,请重试!";return new Result(code,book,msg);}
3、异常处理器
异常要分类处理、放在表现层、使用AOP思想
@RestControllerAdvice //声明此类为异常处理器类 = @ResponseBody + @Component
public class ProjectExceptionAdvice {@ExceptionHandler(Exception.class) //定义处理的是哪一种异常 括号内为异常种类public Result doException(Exception ex){ //将异常对象传入处理方法内System.out.println("此处已经拦截到异常");return new Result(110,null,"产生异常啦");}
}
4、项目异常处理方案
第一步、针对BussinessException、SystemException写配置类,内容相同。
public class BussinessException extends RuntimeException {private Integer code;public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public BussinessException(String message, Integer code) {super(message);this.code = code;}public BussinessException(String message, Throwable cause, Integer code) {super(message, cause);this.code = code;}
第二步、针对可能出现异常地方处理
public Book getById(Integer id) {if(id == 1){throw new BussinessException(Code.BUSSINESS_ERR,"出现错误了");}//将可能出现的异常进行包装,转换成自定义异常try{int i = 1 / 0;}catch(Exception e){throw new SystemException(Code.SYSTEM_TIMEOUT_ERR,"服务器坏;额",e);}return bookDao.getById(id);}
第三步、异常处理器分类三种异常,针对性处理
@RestControllerAdvice //声明此类为异常处理器类 = @ResponseBody + @Component
public class ProjectExceptionAdvice {@ExceptionHandler(SystemException.class) //定义处理的是哪一种异常 括号内为异常种类public Result doSystemExceptionn(SystemException ex){ //将异常对象传入处理方法内//记录日志//发送消息给运维//发送邮件给开发人员 ex对象发送return new Result(ex.getCode(),null,ex.getMessage());}@ExceptionHandler(BussinessException.class) //定义处理的是哪一种异常 括号内为异常种类public Result doBussinessException(BussinessException ex){ //将异常对象传入处理方法return new Result(ex.getCode(),null,ex.getMessage());}//其他异常@ExceptionHandler(Exception.class) //定义处理的是哪一种异常 括号内为异常种类public Result doException(Exception ex){ //将异常对象传入处理方法内System.out.println("此处已经拦截到异常");return new Result(SYSTEM_UNKNOW_ERR,null,"系统繁忙请稍后!");}
}
5、案例:SSM整合标准开发
至于处理SpringMVC拦截静态资源,就利用api处理。
把下面这个类在SpringMvcConfig配置类中扫描到就好了
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");registry.addResourceHandler("/css/**").addResourceLocations("/css/");registry.addResourceHandler("/js/**").addResourceLocations("/js/");registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");}
}
也就是页面操作-----前端没学 没法做喽
第五章、拦截器
1、拦截器概念
2、入门案例
《1、》制作拦截器功能类
将功能类写在controller下,SpringMVC扫描controller时可以直接扫描到
重写API三个方法
@Component
public class ProjectInterceptor implements HandlerInterceptor {public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("ProjectInterceptor...");return true;
//此处若返回false则终止原始方法的执行,接下来的所有都不执行了}public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle...");}public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion...");}
}
《2、》配置拦截器的执行位置
也就是去确定在执行什么请求时执行拦截器
在SpringMvcSupport配置类中重写API ProjectInterceptor 的方法 addInterceptors
来确定要拦截的请求路径
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");registry.addResourceHandler("/css/**").addResourceLocations("/css/");registry.addResourceHandler("/js/**").addResourceLocations("/js/");registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");}@Autowiredprivate ProjectInterceptor projectInterceptor;protected void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");}
}
3、拦截器参数
4、拦截器工作流程分析
5、拦截器链