SpringMVC

学习流程图:

四个学习模块:

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/*");
    }
}

3、拦截器参数

4、拦截器工作流程分析

5、拦截器链

相关推荐
谙弆悕博士1 分钟前
快速学C语言——第19章:C语言常用开发库
c语言·开发语言·算法·业界资讯·常用函数
月落归舟2 分钟前
深入解析Java基础之基础
java·开发语言
折哥的程序人生 · 物流技术专研3 分钟前
《Java 100 天进阶之路》第20篇:Java初始化、构造器、对象创建的过程
java·开发语言·后端·面试
南宫萧幕7 分钟前
基于 Simulink 与 Python 联合仿真的 eVTOL 强化学习全链路实战
开发语言·人工智能·python·算法·机器学习·控制
电魂泡哥9 分钟前
CMS垃圾回收
java·jvm·算法
csbysj202022 分钟前
Perl 运算符
开发语言
Amctwd28 分钟前
【Python】从Excel中按行提取图片
java·python·excel
啃臭37 分钟前
AOP和反射
java·spring boot
西凉的悲伤44 分钟前
java 使用PNG图片隐写文件
java·图片隐写·png
有梦想的小何1 小时前
Cursor AI 编程实战(篇一):Prompt 与案例总结
java·linux·prompt·ai编程