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、拦截器链

相关推荐
起名字真南17 分钟前
【OJ题解】C++实现字符串大数相乘:无BigInteger库的字符串乘积解决方案
开发语言·c++·leetcode
爬山算法22 分钟前
Maven(28)如何使用Maven进行依赖解析?
java·maven
tyler_download28 分钟前
golang 实现比特币内核:实现基于椭圆曲线的数字签名和验证
开发语言·数据库·golang
小小小~29 分钟前
qt5将程序打包并使用
开发语言·qt
hlsd#29 分钟前
go mod 依赖管理
开发语言·后端·golang
小春学渗透31 分钟前
Day107:代码审计-PHP模型开发篇&MVC层&RCE执行&文件对比法&1day分析&0day验证
开发语言·安全·web安全·php·mvc
杜杜的man33 分钟前
【go从零单排】迭代器(Iterators)
开发语言·算法·golang
亦世凡华、34 分钟前
【启程Golang之旅】从零开始构建可扩展的微服务架构
开发语言·经验分享·后端·golang
2401_857439691 小时前
SpringBoot框架在资产管理中的应用
java·spring boot·后端
怀旧6661 小时前
spring boot 项目配置https服务
java·spring boot·后端·学习·个人开发·1024程序员节