学习流程图:
四个学习模块:
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依赖坐标
java
<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接受请求与响应)
java
@Controller //定义spring的bean
public class UserController {
@RequestMapping("/save")// 设置当前操作的访问URL路径
@ResponseBody //设置以下的方法是执行响应的方法
// 定义具体的处理请求操作,向外返回JSON数据
public String save(){
System.out.println("此处是处理请求的方法");
return "{'module':'springmvc'}";
}
}
3、创建spring配置类,扫描bean
java
//创建spring配置类,扫描controller对应的bean
@Configuration
@ComponentScan("com.itheima.controller")
public class SpringmvcConfig {
}
4、初始化Servlet容器,加载配置类,设置请求方法
创建一个web容器并加载spring配置类完成注册;设置请求映射路径,直接"/"表示全部
java
//定义一个Servlet容器启动的配置类,在里面加载spring的配置
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
//让Tomcat能够加载SpringMVC容器的配置
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringmvcConfig.class);
return ctx;
}
//设置哪些请求归属SpringMVC处理
@Override
protected 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配置类
java
@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配置类
java
@Configuration
@ComponentScan("com.itheima.controller")
public class SpringMvcConfig {
}
Servlet容器配置类 ServletContainersInitConfig :加载Spring与SpringMVC容器
java
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
// springMVC容器加载配置
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
// Spring容器加载配置
@Override
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringConfig.class);
return ctx;
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
5、PostMan
网页调试与发送http请求的插件。
作用:常用于接口测试。
第二章、请求与响应
1、请求映射路径
在类上统一设置当前控制器方法请求访问路径前缀。
java
@Controller
@RequestMapping("/user") //访问路径前缀 ,目的是区别不同的controller类
public class UserController {
@RequestMapping("/save") //具体的方法的请求路径
@ResponseBody
public String save(){
System.out.println("此处是usercontroller类中的save方法");
return "{'我要吃饭了':'真的好饿'}";
}
@RequestMapping("/delete")
@ResponseBody
public String delete(){
System.out.println("此处是us二controller内的delete方法");
return "{'我真的要饿死了':'一点也不好玩'";
}
}
2、请求参数
直接在方法内写入形式参数即可。在发出请求的时候输入参数就会传入。
《1、普通参数》
请求url(?表示接下来的是参数 使用&分隔不同的参数)
java
http://localhost:8080/springMVC_02_bean_load_war/commonParam?name=我是你爹 & age=100
方法写入形参
URL中参数名 与方法内的形参名会自动映射,相同则直接传参。 如果不匹配使用@RequestParam("里面写上前端的对应的名称")
java
@RequestMapping("/commonParam")
@ResponseBody
public 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类中使用过滤器处理
java
//乱码处理 重写getServletFilters()方法
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[] {filter};
}
post请求方法----参数在请求体
《2、POJO参数》
实际开发中,是接收大量参数组成一个实体类
定义一个实体类,声明属性、toString()以及setter()&getter()
将此实体类对象作为方法内的 形参
java
//POJO参数
@RequestMapping("/pojoParam")
@ResponseBody
public String pojoParam(User user){
System.out.println("pojo参数传递user --》" + user);
return "{'module':'pojo param'}";
}
基于本框架,前端页面传的所有参数属性,会自动根据名称和实体类的属性匹配、赋值。
《3、POJO嵌套》
对应引用类型传参,正常在后端就正常定义实体类就行了。
但在前端传参的时候,aa.bb 前者是引用对象实例,后者是传参属性
《4、数组参数》
对于数组参数,只需要在前端传参时将名称全部写为数组名即可。
java
//数组参数
@RequestMapping("/arrayParam")
@ResponseBody
public String arrayParam(String[] arr){
System.out.println("数组参数传递为:" + Arrays.toString(arr));
return "{'module':'arrayparam'";
}
《5、集合参数》
java
//集合参数
@RequestMapping("/listParam")
@ResponseBody
public 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数据可以转化为被后端接收的数据
java
@EnableWebMvc //开启由JSON数据转换为List集合数据
《1、集合参数:json格式》
java
//集合参数 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格式》
java
//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格式》
java
//集合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 作用:设置当前控制器返回值为响应体
响应页面--返回页面文件名
java
//响应页面、跳转页面
@RequestMapping("/toJumpPage")
public String toJumpPage(){
System.out.println("成功跳转页面");
return "page.jsp";
}
响应数据--文本数据
文本数据要放在响应体内!!!使用 @ResponseBody 标明!!!1
java
// 响应文本数据
@RequestMapping("/toText")
@ResponseBody
public String toText(){
System.out.println("响应返回文本数据");
return "Response text";
}
响应数据--json数据
json数据要放在响应体内
java
// 响应pojo对象
@RequestMapping("toJsonPOJO")
@ResponseBody
public User toJsonPOJO(){
System.out.println("响应返回json对象数据");
User user = new User();
user.setName("我是你大爷的太祖宗");
user.setAge(100);
return user;
}
// 响应pojo对象
@RequestMapping("toJsonlistPOJO")
@ResponseBody
public 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 的路径要改为类名 ;并且指定访问方法
java
@RequestMapping(value = "/users",method = RequestMethod.POST) //具体的方法的请求路径
@ResponseBody
public String save(){
System.out.println("此处是usercontroller类中的save方法");
return "{'我要吃饭了':'真的好饿'}";
}
传参:
value要指定参数路径位置/路径/{参数名};形参要添加@PathVariable 表示参数从路径中得到
java
@RequestMapping(value = "/users",method = RequestMethod.POST) //具体的方法的请求路径
@ResponseBody
public String save(){
System.out.println("此处是usercontroller类中的save方法");
return "{'我要吃饭了':'真的好饿'}";
}
@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
@ResponseBody
public String delete(@PathVariable Integer id){
System.out.println("此处是us二controller内的delete方法" + id);
return "{'我真的要饿死了':'一点也不好玩'";
}
@RequestMapping(value = "/users",method = RequestMethod.PUT)
@ResponseBody
public String update(@RequestBody User user){
System.out.println("此处是us二controller内的update方法" + user);
return "{'module':'erertrgtrt'}";
}
以后开发中,基本上都是将数据封装成pojo,然后通过json串传递。
2、RESTful入门案例
java
@RequestMapping(value = "/users",method = RequestMethod.POST) //具体的方法的请求路径
@ResponseBody
public String save(){
System.out.println("此处是usercontroller类中的save方法");
return "{'我要吃饭了':'真的好饿'}";
}
@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
@ResponseBody
public String delete(@PathVariable Integer id){
System.out.println("此处是us二controller内的delete方法" + id);
return "{'我真的要饿死了':'一点也不好玩'";
}
@RequestMapping(value = "/users",method = RequestMethod.PUT)
@ResponseBody
public String update(@RequestBody User user){
System.out.println("此处是us二controller内的update方法" + user);
return "{'module':'erertrgtrt'}";
}
3、REST快速开发(简化代码)
对于相同的注解、mapping,直接在类前面写。
@RestController = @Controller + @ResponseBody
对于映射直接写请求方法+mapping,需要单独添加参数后面加。
java
@RestController
@RequestMapping("/books")
public class BookController {
@PostMapping
public 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':'你爹爹的}";
}
@PutMapping
public 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配置类中
java
@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。
创建含有不同属性的构造方法,针对不同请求方法返回不同结果
java
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;
}
创建状态码类,以便针对前端确认 请求方法及正误
java
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)
将最终返回结果都封装成指定的格式
java
public Result save(@RequestBody Book book) {
boolean flag = bookService.save(book);
return new Result(flag ? Code.SAVE_OK : Code.SAVE_ERR,flag);
}
@PutMapping
public 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思想
java
@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写配置类,内容相同。
java
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;
}
第二步、针对可能出现异常地方处理
java
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);
}
第三步、异常处理器分类三种异常,针对性处理
java
@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配置类中扫描到就好了
java
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Override
protected 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三个方法
java
@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
来确定要拦截的请求路径
java
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
}
@Autowired
private ProjectInterceptor projectInterceptor;
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
}
}