SpringMvc学习笔记

一.SpringMVC入门

1.概念

基于Java实现MVC模型的的web层框架

优点:相比servlet开发更简单高效,且更加灵活

2.入门案例

(1)导入jar包

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.10.RELEASE</version>
  </dependency>
  <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
  </dependency>
</dependencies>

(2)创建SpringMVC控制类---相当于servlet界面


@Controller//定义表现层控制器bean
public class UserController {
    @RequestMapping("/save")//配置访问路径
    @ResponseBody       //响应体---设置当前操作返回结果为指定json数据(本质上是一个字符串信息)
    public String save(){
        System.out.println("hello,springmvc");
        return "{'info':hello,mvc}";
    }
    
    @RequestMapping("/select")
    @ResponseBody
    public String select(){
        System.out.println("select...");
        return "{'info':select...}";
    }

}

有三个新的注解

(3)初始化SpringMVC环境配置


@Configuration
@ComponentScan("com.dongnan")

public class SpringConfig {
}

(4)初始化Servlet容器,加载SpringMVC环境

//web容器配置类
public class ServletContainerInitConfig extends AbstractDispatcherServletInitializer {
    //加载springmvc配置类,产生springmvc容器(本质还是spring容器)
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext ctt=new AnnotationConfigWebApplicationContext();
        //加载指定配置类
        ctt.register(SpringConfig.class);
        return ctt;
    }
    //哪些请求归springmvc管理---设置由springmvc控制器处理的请求映射路径
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
    //加载springmvc配置类,产生springmvc容器(本质还是spring容器)
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }
}

3.工作流程

本质是将SpringMVC的配置加载到Tomcat容器,并且设定之后的请求都经由SpringMVC来处理

4.SpringMVC和Spring加载各自Bean的配置格式

a.因为Controller类的Bean归SpringMVC容器管理,dao,service等Bean由Spring容器管理,因此需要在设置Bean扫描时加以区分:

(1)精准匹配

b.Filter过滤:在Spring的Bean扫描注解中添加过滤条件

@Configuration
//设置spring配置类加载bean时的过滤规则,当前要求排除掉表现层对应的bean
//excludeFilters属性:设置扫描加载bean时,排除的过滤规则
//type属性:设置排除规则,当前使用按照bean定义时的注解类型进行排除
//classes属性:设置排除的具体注解类,当前设置排除@Controller定义的bean
@ComponentScan(value="com.dongnan",
    excludeFilters = @ComponentScan.Filter(
        type = FilterType.ANNOTATION,
        classes = Controller.class
    )
)
public class SpringConfig {
}

c.将二者加载到同一个环境

(2)将二者加载到web容器中:

a.源码:


public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(SpringMvcConfig.class);
        return ctx;
    }
    protected WebApplicationContext createRootApplicationContext() {
        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
        ctx.register(SpringConfig.class);
        return ctx;
    }
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

}

b.使用子类简化开发

public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {

    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};
    }

    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

5.postman测试接口工具

二.请求与响应

1.设置请求路径前缀

2.Controller接收请求参数

(1)普通参数

在Response方法体添加形参

注:对post请求中文乱码的处理:在web容器配置类中重写方法设置Filter过滤

    @Override
    //给web容器设置一个设置post请求字符格式的filter
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter filter=new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        return new Filter[]{filter};
    }

(2)pojo类

(3)带pojo属性的pojo类

(4)数组

(5)集合---加@RequestParam

3.json请求数据传递和接收

(1)导入Json转为pojo的依赖

<dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.0</version>
    </dependency>

(2)在SpringMvcConfig中添加开启json转化功能的注解---@EnableWebMvc

(3)Response方法参数添加@RequestBody注解

  //集合参数:json格式
    //1.开启json数据格式的自动转换,在配置类中开启@EnableWebMvc
    //2.使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据
    @RequestMapping("/listParamForJson")
    @ResponseBody
    public String listParamForJson(@RequestBody List<String> likes){
        System.out.println("list common(json)参数传递 list ==> "+likes);
        return "{'module':'list common for json param'}";
    }

注:

4.日期类型参数请求

    //使用@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'}";
    }

5.响应

(1)响应页面

    //响应页面/跳转页面
    //返回值为String类型,设置返回值为页面名称,即可实现页面跳转
    @RequestMapping("/toJumpPage")
    public String toJumpPage(){
        System.out.println("跳转页面");
        return "page.jsp";
    }

(2)响应数据---需要加@ResponseBody,用于将数据转为JSON返回

文本数据,pojo对象,pojo集合对象

    //响应POJO对象
    //返回值为实体类对象,设置返回值为实体类类型,即可实现返回对应对象的json数据,需要依赖@ResponseBody注解和@EnableWebMvc注解
    @RequestMapping("/toJsonPOJO")
    @ResponseBody
    public User toJsonPOJO(){
        System.out.println("返回json对象数据");
        User user = new User();
        user.setName("itcast");
        user.setAge(15);
        return user;
    }

三.REST资源访问风格

1.优点

---隐藏了资源的访问行为

---根据REST风格进行资源访问称为RESTful

2.入门案例

(1)设定http访问行为---8种提交方式

(2)如果有路径变量,则做出两处修改

@Controller
public class UserController {    
    @RequestMapping(value = "/users",method = RequestMethod.POST)
    @ResponseBody
    public String save(){
        System.out.println("user save...");
        return "{'module':'user save'}";
    }
  

    //1.访问路径中用{...}声明方法形参
    //2.形参中加注解表明是路径变量
    //@PathVariable注解用于设置路径变量(路径参数),要求路径上设置对应的占位符,并且占位符名称与方法形参名称相同
    @RequestMapping(value = "/users/{id}", method = RequestMethod.GET)
    @ResponseBody
    public String getById(@PathVariable int id) {
        System.out.println("user getById..." + id);
        return "{'module':'user getById'}";
    }

}

3.简化开发

将访问路径,@ResponseBody注解和提交方式名等重复部分提取

@RestController//合并@Controller和@ResponseBody
@RequestMapping("/users")//提取共同路径
public class UserController {
    @PostMapping//代表请求方法
    public String save(){
        System.out.println("user save...");
        return "{'module':'user save'}";
    }
    @GetMapping("/{id}")//代表请求方法,设置额外路径
    public String getById(@PathVariable int id) {
        System.out.println("user getById..." + id);
        return "{'module':'user getById'}";
    }
}

4.实现案例

(1)设置对静态资源的访问放行

访问webapp下的静态资源被SpringMvc拦截

@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
    //设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载
    @Override
    protected 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/");
    }
}

需要被SpringMvcConfig容器扫描

@Configuration
@ComponentScan({"com.itheima.controller","com.itheima.config"})//添加扫描
@EnableWebMvc
public class SpringMvcConfig {
}

注:几个错误点:

1.路径配置要正确

2.添加Configuration注解

3.确认SpringMvcConfig中能扫描到SpringMvcSupport,不要扫描到SpingConfig中

四.ssm整合

1.整合案例

1.整合Spring配置   

创建web-maven项目,导入依赖

创建包结构

Spring-->Mybatis--->SpringMvc

2.完成业务层功能

3.接口测试

2.表现层数据封装

(1)数据模型

//封装返回数据---根据需求自定义
public class Result {
    private Object data;//数据体
    private Integer code;//状态码
    private String msg;//提示信息

    //根据需求自定义构造方法(一般分有msg和无msg)
    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;
    }
    //getter,setter...
}
//存放状态码
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;
}

实际调用

@RestController
@RequestMapping("/books")
public class BookController {
    @Autowired
    private BookService bookService;

    @PostMapping
    public Result save(@RequestBody Book book) {
        boolean flag = bookService.save(book);
        return new Result(flag ? Code.SAVE_OK : Code.SAVE_ERR, flag);
    }

    @GetMapping
    public Result getAll() {
        List<Book> books = bookService.getAll();
        Integer code = books != null ? Code.GET_OK : Code.GET_ERR;
        String msg = books != null ? "" : "数据查询失败,请重试!";
        return new Result(code, books, msg);
    }
}

3.异常处理器

出现异常后将异常在表现层抛出

(1)异常处理器定义

//@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器
@RestControllerAdvice
public class ProjectExceptionAdvice {
    //用于设置当前处理器类对应的异常类型
    @ExceptionHandler(Exception.class)
    public Result doExecption(Exception ex) {
        System.out.println("发现异常");
        return new Result(000, null, "出现异常");
    }
}

4.项目异常处理

(1)定义业务异常和系统异常的两个异常类

//自定义异常处理器,用于封装异常信息,对异常进行分类
public class BusinessException extends RuntimeException{
    private Integer code;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public BusinessException(Integer code, String message) {
        super(message);
        this.code = code;
    }

    public BusinessException(Integer code, String message, Throwable cause) {
        super(message, cause);
        this.code = code;
    }

}

public class SystemException extends RuntimeException{
    private Integer code;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public SystemException(Integer code, String message) {
        super(message);
        this.code = code;
    }

    public SystemException(Integer code, String message, Throwable cause) {
        super(message, cause);
        this.code = code;
    }

}

(2)定义异常状态码

public class Code {
 

    public static final Integer SYSTEM_ERR = 50001;
    public static final Integer SYSTEM_TIMEOUT_ERR = 50002;
    public static final Integer SYSTEM_UNKNOW_ERR = 59999;

    public static final Integer BUSINESS_ERR = 60002;



}

(3)在业务层中可能出现异常的地方包装抛出自定义异常

  public Book getById(Integer id) {
        //模拟业务异常,包装成自定义异常
        if(id == 1){
            throw new BusinessException(Code.BUSINESS_ERR,"请不要使用你的技术挑战我的耐性!");
        }
        //模拟系统异常,将可能出现的异常进行包装,转换成自定义异常
        try{
            int i = 1/0;
        }catch (Exception e){
            throw new SystemException(Code.SYSTEM_TIMEOUT_ERR,"服务器访问超时,请重试!",e);
        }
        return bookDao.getById(id);
    }

(4)异常处理器中处理异常

//@RestControllerAdvice用于标识当前类为REST风格对应的异常处理器
@RestControllerAdvice
public class ProjectExceptionAdvice {
    //@ExceptionHandler用于设置当前处理器类对应的异常类型
    @ExceptionHandler(SystemException.class)
    public Result doSystemException(SystemException ex){
        //记录日志
        //发送消息给运维
        //发送邮件给开发人员,ex对象发送给开发人员
        return new Result(ex.getCode(),null,ex.getMessage());
    }

    @ExceptionHandler(BusinessException.class)
    public Result doBusinessException(BusinessException ex){
        return new Result(ex.getCode(),null,ex.getMessage());
    }

    //除了自定义的异常处理器,保留对Exception类型的异常处理,用于处理非预期的异常
    @ExceptionHandler(Exception.class)
    public Result doOtherException(Exception ex){
        //记录日志
        //发送消息给运维
        //发送邮件给开发人员,ex对象发送给开发人员
        return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系统繁忙,请稍后再试!");
    }
}

5.拦截器

(1)概念

(2)入门

a.声明interceptor类,定义拦截器的功能

@Component
//定义拦截器类,实现HandlerInterceptor接口
//注意当前类必须受Spring容器控制
public class ProjectInterceptor implements HandlerInterceptor {
    //原始方法调用前执行的内容
    //返回值类型可以拦截控制的执行,true放行,false终止
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("访问前拦截");
        return true;
    }

    //原始方法调用后执行的内容
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("访问后拦截");
    }

    //原始方法调用完成后执行的内容
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("访问最终拦截");
    }
}



重写三个方法代表不同执行时机

b.定义配置类实现接口WebMvcConfigurationSupport

c.配置制定拦截器和拦截位置

@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
    @Autowired
    private ProjectInterceptor projectInterceptor;
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        //配置拦截器
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
    }
}

SpringMvcConfig中要扫描到配置类

(3)参数

(4)拦截器链

6.配置类的简化开发

@Configuration
@ComponentScan({"com.itheima.controller"})
@EnableWebMvc
//实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性
public class SpringMvcConfig implements WebMvcConfigurer {
    @Autowired
    private ProjectInterceptor projectInterceptor;
    @Autowired
    private ProjectInterceptor2 projectInterceptor2;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //配置多拦截器
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
        registry.addInterceptor(projectInterceptor2).addPathPatterns("/books","/books/*");
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值