web开发

1.传统的接口和Restful风格的区别

传统的api接口:

@RequestMapping("saveUser")
public String saveUser(){
    return "保存用户";
}
@RequestMapping("deleteUser")
public String deleteUser(){
    return "删除用户";
}
@RequestMapping("getUser")
public String getUser(){
    return "查询用户";
}
@RequestMapping("editUser")
public String editUser(){
    return "修改用户";
}

restful风格的api接口:

只需要一个请求接口

@RequestMapping(value = "user",method = RequestMethod.POST)
public String saveUser(){
    return "保存用户";
}
@RequestMapping(value = "user",method = RequestMethod.DELETE)
public String deleteUser(){
    return "删除用户";
}
@RequestMapping(value = "user",method = RequestMethod.GET)
public String getUser(){
    return "查询用户";
}
@RequestMapping(value = "user",method = RequestMethod.PUT)
public String editUser(){
    return "修改用户";
}

简写方式:@xxxMapping

@PostMapping("user")
public String saveUser(){
    return "保存用户";
}

2.基本参数和基本注解

2.1 注解

常见的参数注解 @PathVariable、@RequestHeader、@ModelAttribute、@RequestParam、@RequestAttribute、@MatrixVariable、@CookieValue、@RequestBody

@PathVariable

路径变量

// 请求url: http://localhost:8080/user/2    
@GetMapping("user/{id}")
public void getUser(@PathVariable("id")Integer id){
    System.out.println("id = " + id);
}
// 获取请求中所有的参数
// 请求url: http://localhost:8080/user/2/tr
@GetMapping("user/{id}/{userName}")
public void getUsers(@PathVariable Map<String, String> pv){
    System.out.println("pv = " + pv);
}

@RequestHeader

获取请求头信息

// 获取所有请求头信息
@GetMapping("user")
public void testRequestHeader(@RequestHeader Map<String, String> headers){
    System.out.println("headers = " + headers);
}

@RequestParam

获取请求参数

//请求url: http://localhost:8080/user?userName=test 也可以通过map接收所有参数
@GetMapping("user")
public String test(@RequestParam("userName") String userName){
    return userName;
}

@CookieValue

获取cookie值

//获取key=cookie_key 的所有cookie信息
    @GetMapping("testCookieValue")
    public void testCookie(@CookieValue("cookie_key") Cookie cookie){
        System.out.println("cookie = " + cookie);
    }

@RequestBody

获取请求体

//需要使用post请求 将整个表单提交的key value全部获取
@GetMapping("testRequestBody")
public void postUser(@RequestBody String content){
    System.out.println("content = " + content);
}

@RequestAttribute

快速取出请求域中的信息

@GetMapping("/goto")
public String gotoPage(HttpServletRequest request){
    request.setAttribute("msg","成功了...");
    return "forward:/success";
}

@ResponseBody
@GetMapping("/success")
public String test(@RequestAttribute("msg") String msg,HttpServletRequest request){
    Object msg1 = request.getAttribute("msg");
    System.out.println("msg1 = " + msg1.toString());
    System.out.println("msg = " + msg);
    return "ok";
}

@MatrixVariable

矩阵变量

//1、语法: 请求路径:/cars/sell;low=34;brand=byd,audi,yd
//2、SpringBoot默认是禁用了矩阵变量的功能
//      手动开启:原理。对于路径的处理。UrlPathHelper进行解析。
//              removeSemicolonContent(移除分号内容)支持矩阵变量的
//3、矩阵变量必须有url路径变量才能被解析
@GetMapping("/cars/{path}")
public Map carsSell(@MatrixVariable("low") Integer low,
                    @MatrixVariable("brand") List<String> brand,
                    @PathVariable("path") String path){
    Map<String,Object> map = new HashMap<>();

    map.put("low",low);
    map.put("brand",brand);
    map.put("path",path);
    return map;
}

// /boss/1;age=20/2;age=10

@GetMapping("/boss/{bossId}/{empId}")
public Map boss(@MatrixVariable(value = "age",pathVar = "bossId") Integer bossAge,
                @MatrixVariable(value = "age",pathVar = "empId") Integer empAge){
    Map<String,Object> map = new HashMap<>();

    map.put("bossAge",bossAge);
    map.put("empAge",empAge);
    return map;

}

手动开启矩阵变量

// 开启矩阵变量
@Bean
public WebMvcConfigurer webMvcConfigurer(){
    return new WebMvcConfigurer() {
        @Override
        public void configurePathMatch(PathMatchConfigurer configurer) {
            UrlPathHelper helper = new UrlPathHelper();
            // 不移除 ;后面的内容
            helper.setRemoveSemicolonContent(false);
            configurer.setUrlPathHelper(helper);
        }
    };
}

3.静态资源访问

3.1、静态资源目录

只要静态资源放在类路径下: /static (or /public or /resources or/META-INF/resources)

访问 : 当前项目根路径/ + 静态资源名

原理: 静态映射/**。

请求进来,先去找Controller看能不能处理。不能处理的所有请求又都交给静态资源处理器。静态资源也找不到则响应404页面

改变默认静态资源路径

# 默认无前缀,http://localhost:8080/test/test.css
spring:
  mvc:
    static-path-pattern: /test/**
  # 自定义静态资源包 
  resources:
    static-locations: [classpath:/test/]

3.2、自定义 Favicon

favicon.ico 放在静态资源目录下即可。

spring:
#  mvc:
#    static-path-pattern: /test/**   这个配置会导致 Favicon 功能失效

4.拦截器

4.1、自定义拦截器

继承HandlerInterceptor接口

@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

    // 请求之前
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 打印日志
        log.info("拦截路径{}",request.getRequestURI());
        HttpSession session = request.getSession();
        Object login = session.getAttribute("login");
        if (login != null) {
            return true;
        }
        // 未登录,转发到登录页面
        // request.getRequestDispatcher("/login").forward(request,response);
        response.sendRedirect("/login"); //重定向
        return false;
    }
    // 请求完成之后
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }
    // 页面渲染之后
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}

4.2、将自定义的拦截器注入ioc

继承WebMvcConfigurer接口

@Configuration
public class MyWebConfig implements WebMvcConfigurer{
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                //拦截所有请求
                .addPathPatterns("/**")
                //不拦截的请求
                .excludePathPatterns("/login","/err");
    }
}

5.文件上传

5.1、准备一个表单

<form action="/upload" enctype="multipart/form-data" method="post">
    <input type="file" name="image"><br>
    <input type="file" name="images" multiple><br>
    <input type="text" name="username"><br>
    <input type="password" name="password"><br>
    <input type="submit" value="提交">
</form>

5.2、准备接口

@PostMapping("/upload")
public String uploadForm(@RequestParam Map<String, String> kvParam,
                       @RequestPart("image")MultipartFile image,
                       @RequestPart("images")MultipartFile[] images) throws IOException {
    System.out.println("kvParam = " + kvParam);
    System.out.println(image.isEmpty());
    System.out.println(images.length);
    if (!image.isEmpty()) { //不为空
        // 保存到 D://images//
        image.transferTo(new File("D://image//"));
    }
    return "上传成功";
}

5.3、配置文件大小

如果上传的文件大小超过1M会报错,需要手动开启配置

spring:
  servlet:
    multipart:
      # 单文件上传大小
      max-file-size: 1MB
      # 文件上传总大小
      max-request-size: 10MB

6.异常处理

6.1、错误处理

  • 默认情况下,Spring Boot提供/error处理所有错误的映射
  • 对于机器客户端,它将生成JSON响应,其中包含错误,HTTP状态和异常消息的详细信息。对于浏览器客户端,响应一个“ whitelabel”错误视图,以HTML格式呈现相同的数据
  • 要对其进行自定义,添加View解析为error
  • 要完全替换默认行为,可以实现 ErrorController并注册该类型的Bean定义,或添加ErrorAttributes类型的组件以使用现有机制但替换其内容。
  • error/下的4xx,5xx页面会被自动解析;

6.2、定制错误处理

  • 自定义错误页 error/404.html error/5xx.html;有精确的错误状态码页面就匹配精确,没有就找 4xx.html;如果都没有就触发白页

    • resource/error
  • @ControllerAdvice+@ExceptionHandler处理全局异常;底层是 ExceptionHandlerExceptionResolver 支持的

    • @ControllerAdvice
      public class TestException {
          @ExceptionHandler({ArithmeticException.class})
          @ResponseBody
          public String HandlesArithmeticException() {
              return "自定义处理运算异常";
          }
      }
      
  • @ResponseStatus+自定义异常 ;底层是 ResponseStatusExceptionResolver ,把responsestatus注解的信息底层调用 response.sendError(statusCode, resolvedReason);tomcat发送的/error

    • @ResponseStatus(value = HttpStatus.FORBIDDEN,reason = "用户过多拒绝访问")
      public class UserTooManyException extends RuntimeException {
          public UserTooManyException(String message) {
              super(message);
          }
      }
      
  • Spring底层的异常,如 参数类型转换异常;DefaultHandlerExceptionResolver 处理框架底层的异常。

    • response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());

Q.E.D.

同是风华正茂,怎可甘拜下风