Java框架(九)--Spring Boot入门(2)

SpringBoot 核心功能讲解

SpringBoot之web请求静态资源

我们可以在浏览器访问src/main/resources/static目录下的静态资源,在此目录下新建test.html

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>静态资源文件title>
head>
<body>
    <div id="test">
        Hello SpringBoot~
    div>
body>
html>

运行项目,浏览器访问http://localhost:8090/test.html
Java框架(九)--Spring Boot入门(2)_第1张图片
也可以访问之前放的图片
Java框架(九)--Spring Boot入门(2)_第2张图片
我们也可以在application.yml中定义更多层级的目录的

spring:
  banner:
    location: classpath:static/banner.txt
  mvc:
    static-path-pattern: /abc/**

Java框架(九)--Spring Boot入门(2)_第3张图片
我们先改回去,然后在src/main/resources/static目录下创建index.html,该文件为默认首页,访问时不需要文件名。

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>首页title>
head>
<body>
    <div id="test">
        Hello Index~
    div>
body>
html>

然后启动项目,浏览器直接访问http://localhost:8090/
Java框架(九)--Spring Boot入门(2)_第4张图片
在src/main/resources/static引入文件名为favicon.ico的图标,maven install项目之后运行项目,浏览器再访问的时候浏览器tab上已经有了改图标
Java框架(九)--Spring Boot入门(2)_第5张图片

通过Lombok提高开发效率以及日志设置

首先打开pom.xml文件引入Lombok依赖


		<dependency>
			<groupId>org.projectlombokgroupId>
			<artifactId>lombokartifactId>
		dependency>

然后在IDEA通过点击File=>Settings开发设置面板,找到Plugins,然后搜索Lombok安装(本人IDEA是2022版,发现IDEA默认装过了)
Java框架(九)--Spring Boot入门(2)_第6张图片
然后在com.ql.springbootlearn.pojo包下创建Student.java

package com.ql.springbootlearn.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    public String name;
    public Integer age;
}

其中@Data生成get和set方法,@ToString生成toString方法,@NoArgsConstructor生成默认构造方法,@AllArgsConstructor生成全参构造方法。

然后在HelloController.java中调用

@RestController
@Slf4j
public class HelloController {
...
    @GetMapping("getStudent")
    public Object getStudent(){
        Student student = new Student();
        student.setName("Smith");
        student.setAge(28);
        Student student1 = new Student("Jams", 34);
        log.debug(student.toString());
        log.info(student.toString());
        log.warn(student.toString());
        log.error(student.toString());
        return student;
    }
}

其中@Slf4j也是Lombok的注解,注入日志组件

运行项目,浏览器访问http://localhost:8090/getStudent
Java框架(九)--Spring Boot入门(2)_第7张图片
Java框架(九)--Spring Boot入门(2)_第8张图片
因为SpringBoot项目默认日志级别是info,所以debug日志没显式。

注意:当然Lombok也有缺点,在团队开发的时候,只要有一个人使用,所有人必须使用Lombok,不然项目无法编译通过。如果是个人的话,完全没有问题。

Restful 接口请求风格

GET 主要用于查询类的操作。
POST 主要用于Form表单提交或相对安全的一些请求。主要保存新的数据。
PUT 主要用于数据的修改。
DELETE 用户数据的删除。
有些公司强制要求用四种请求。另外有些公司使用的是弱规范,就是查询使用GET,增删改使用POST。

在com.ql.springbootlearn.controller包下创建StuController.java

package com.ql.springbootlearn.controller;

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/stu")
public class StuController {
    @GetMapping("get")
    public String getStu(){
        return "查询Stu";
    }
    @PostMapping("create")
    public String crrateStu(){
        return "新增Stu";
    }
    @PutMapping("update")
    public String updateStu(){
        return "修改Stu";
    }
    @DeleteMapping("delete")
    public String deleteStu(){
        return "删除Stu";
    }
}

运行项目,打开postman测试
Java框架(九)--Spring Boot入门(2)_第9张图片
Java框架(九)--Spring Boot入门(2)_第10张图片

Java框架(九)--Spring Boot入门(2)_第11张图片
Java框架(九)--Spring Boot入门(2)_第12张图片

SpringBoot 之接受参数的常用注解

@RequestParam 用于获得URL中的请求参数,如果参数变量名保持一致,该注解可以省略。
@PathVarible 用于获得路径的参数
@RequestBody 用于获得请求的body
@RequestHeader 用于获得请求头中的一些参数
@CookieValue 用于获得Cookie中一些参数

打开StuController.java修改getStu方法

    @GetMapping("{stuId}/get")
    public String getStu(@PathVariable("stuId") String stuId,
                         @RequestParam Integer id,
                         @RequestParam String name){
        log.info("stuId="+ stuId);
        log.info("id="+ id);
        log.info("name="+ name);
        return "查询Stu";
    }

运行项目,打开postman请求测试
Java框架(九)--Spring Boot入门(2)_第13张图片
Java框架(九)--Spring Boot入门(2)_第14张图片
打开StuController.java修改crrateStu方法

    @PostMapping("create")
    public String crrateStu(@RequestBody Map<String, Object> map,
                            @RequestHeader("token") String token,
                            @CookieValue("clientId") String clientId,
                            HttpServletRequest request){
        log.info("token="+token);
        log.info("clientId="+clientId);
        log.info("map="+map.toString());
        String requestHeader = request.getHeader("token");
        log.info("requestHeader="+requestHeader);
        return "新增Stu";
    }

运行项目,打开postman请求测试
Java框架(九)--Spring Boot入门(2)_第15张图片
Java框架(九)--Spring Boot入门(2)_第16张图片
Java框架(九)--Spring Boot入门(2)_第17张图片

SpringBoot 之接口返回响应对象

在com.ql.springbootlearn.utils包下新增接口返回响应JSONResult工具类

package com.ql.springbootlearn.utils;

/**
 * 自定义响应数据结构
 * 本类可提供给 H5/ios/安卓/公众号/小程序 使用
 * 前端接受此类数据(json object)后,可自行根据业务去实现相关功能
 * 200: 表示成功
 * 500: 表示错误,错误信息在msg字段中
 */
public class JSONResult {
    private Integer status;//响应业务状态
    private String msg;//响应消息
    private Object data;//响应中的数据

    public static JSONResult build(Integer status, String msg, Object data){
        return new JSONResult(status, msg, data);
    }

    public static JSONResult ok(Object data){
        return new JSONResult(data);
    }

    public static JSONResult ok(){
        return new JSONResult(null);
    }

    public static JSONResult errorMsg(String msg){
        return new JSONResult(500, msg, null);
    }

    public JSONResult() {
    }

    public JSONResult(Integer status, String msg, Object data) {
        this.status = status;
        this.msg = msg;
        this.data = data;
    }

    public JSONResult(Object data){
        this.status = 200;
        this.msg = "OK";
        this.data = data;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

然后修改HelloController.java的getStudent方法测试

    @GetMapping("getStudent")
    public JSONResult getStudent(){
        Student student = new Student();
        student.setName("Smith");
        student.setAge(28);
        Student student1 = new Student("Jams", 34);
        log.debug(student.toString());
        log.info(student.toString());
        log.warn(student.toString());
        log.error(student.toString());
        return JSONResult.errorMsg("调用接口出现异常");
        //return JSONResult.ok(stu);
    }

Java框架(九)--Spring Boot入门(2)_第18张图片

    @GetMapping("getStudent")
    public JSONResult getStudent(){
        Student student = new Student();
        student.setName("Smith");
        student.setAge(28);
        Student student1 = new Student("Jams", 34);
        log.debug(student.toString());
        log.info(student.toString());
        log.warn(student.toString());
        log.error(student.toString());
        //return JSONResult.errorMsg("调用接口出现异常");
        return JSONResult.ok(stu);
    }

Java框架(九)--Spring Boot入门(2)_第19张图片

SpringBoot实现文件上传

打开src/main/resources/static/test.html文件,添加文件上传的代码

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>静态资源文件title>
head>
<body>
    <div id="test">
        Hello SpringBoot~
    div>
    
    <form action="/upload" method="post" enctype="multipart/form-data">
        <div>
            <input type="file" id="file" name="file" value="选择图片"
                accept="image/jpeg,image/jpg,image/png">
        div>
        <div>
            <input type="submit" value="上传文件">
        div>
    form>
body>
html>

打开HelloController.java添加文件上传的方法

    @PostMapping("upload")
    public String upload(MultipartFile file) throws Exception{
        file.transferTo(new File("D:/upload/"+file.getOriginalFilename()));
        return "上传成功";
    }

运行项目,浏览器访问http://localhost:8090/test.html上传文件
Java框架(九)--Spring Boot入门(2)_第20张图片
Java框架(九)--Spring Boot入门(2)_第21张图片
Java框架(九)--Spring Boot入门(2)_第22张图片

SpringBoot 之自定义异常页面

我们在application.yml中添加文件上传的相关配置

spring:
  servlet:
    multipart:
      max-file-size: 200KB # 文件上传大小的限制,设置最大值,不能超过,否则报错
      max-request-size: 2MB # 文件最大请求限制,用于批量

启动项目,浏览器访问http://localhost:8090/test.html上传一个大于200KB的图片
Java框架(九)--Spring Boot入门(2)_第23张图片
Java框架(九)--Spring Boot入门(2)_第24张图片
Java框架(九)--Spring Boot入门(2)_第25张图片
现在报异常之后,页面展示的不友好,所以我们需要自定义一个异常页面。
首先,打开pom.xml文件,引入thymeleaf模板引擎

		
		<dependency>
			<groupId>org.springframework.bootgroupId>
			<artifactId>spring-boot-starter-thymeleafartifactId>
		dependency>

然后在src/main/resources/templates目录下创建error.html页面

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>静态资源文件title>
head>
<body>
    <div id="test" style="color: red">
        系统发生异常,请联系管理员!
    div>
body>
html>

重新运行项目,再上传刚才的图片,返回的是我们写好的页面。
Java框架(九)--Spring Boot入门(2)_第26张图片

SpringBoot 之统一异常封装处理

如果是前后端分离的项目,出现异常就不能返回页面了,应该把异常信息返回去。
在com.ql.springbootlearn包下创建一个GraceExceptionHandler.java统一异常拦截处理类

package com.ql.springbootlearn;

import com.ql.springbootlearn.utils.JSONResult;
import org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 统一异常拦截处理
 * 可以针对异常自定义去处理去捕获,返回指定的类型(json类型)到前端
 */
@ControllerAdvice
public class GraceExceptionHandler {

    @ExceptionHandler(FileSizeLimitExceededException.class)
    @ResponseBody
    public JSONResult returnMaxFileSizeLimit(FileSizeLimitExceededException e){
        return JSONResult.errorMsg("文件大小不能超过200KB");
    }
}

运行项目,再上传刚才的图片测试。
Java框架(九)--Spring Boot入门(2)_第27张图片

SpringBoot 实现拦截器

在com.ql.springbootlearn.controller.interceptor包下创建拦截器UserInfoInterceptor.java

package com.ql.springbootlearn.controller.interceptor;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.thymeleaf.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Slf4j
public class UserInfoInterceptor implements HandlerInterceptor {
    /**
     * 拦截请求,访问Controller之前
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String userId = request.getHeader("userId");
        String userToken = request.getHeader("userToken");
        if(StringUtils.isEmpty(userId) || StringUtils.isEmpty(userToken)){
            log.error("用户校验不通过,信息不完整!");
            return false;
        }
        //假设真实的用户id是1001,用户token是abcxyz
        if(!userId.equalsIgnoreCase("1001") ||
            !userToken.equalsIgnoreCase("abcxyz")){
            log.error("用户权限不通过!");
            return false;
        }
        /**
         * false: 请求被拦截
         * true: 请求放行,可以继续访问后面的Controller
         */
        return true;
    }

    /**
     * 请求访问到Controller之后,渲染视图之前
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    /**
     * 请求访问到Controller之后,渲染视图之后
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

然后注册拦截器,在com.ql.springbootlearn包下创建InterceptorConfig.java拦截器配置类

package com.ql.springbootlearn;

import com.ql.springbootlearn.controller.interceptor.UserInfoInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Bean
    public UserInfoInterceptor userInfoInterceptor(){
        return new UserInfoInterceptor();
    }

    public void addInterceptors(InterceptorRegistry registry){
        //注册拦截器
        registry.addInterceptor(userInfoInterceptor())
                .addPathPatterns("/upload");
    }
}

运行项目,打开postman测试
Java框架(九)--Spring Boot入门(2)_第28张图片
当用户id和token为空时
Java框架(九)--Spring Boot入门(2)_第29张图片
Java框架(九)--Spring Boot入门(2)_第30张图片
当用户id和token错误时
Java框架(九)--Spring Boot入门(2)_第31张图片
Java框架(九)--Spring Boot入门(2)_第32张图片
当所有信息正确时,上传成功。
Java框架(九)--Spring Boot入门(2)_第33张图片

自定义异常与拦截器整合返回JSON对象

首先,在com.ql.springbootlearn.exception包下创建一个自定义异常类MyCustomException

package com.ql.springbootlearn.exception;

/**
 * 自定义异常
 * 目的:
 *  统一处理异常信息
 *  便于解耦,可以在拦截器,控制层,业务层去使用
 */
public class MyCustomException extends RuntimeException{
    public MyCustomException(String errorMsg){
        super(errorMsg);
    }
}

然后在GraceExceptionHandler.java中捕获该异常

package com.ql.springbootlearn.exception;

import com.ql.springbootlearn.utils.JSONResult;
import org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 统一异常拦截处理
 * 可以针对异常自定义去处理去捕获,返回指定的类型(json类型)到前端
 */
@ControllerAdvice
public class GraceExceptionHandler {

    @ExceptionHandler(FileSizeLimitExceededException.class)
    @ResponseBody
    public JSONResult returnMaxFileSizeLimit(FileSizeLimitExceededException e){
        return JSONResult.errorMsg("文件大小不能超过200KB");
    }

    @ExceptionHandler(MyCustomException.class)
    @ResponseBody
    public JSONResult returnMyCustomException(MyCustomException e){
        return JSONResult.errorMsg(e.getMessage());
    }
}

然后在com.ql.springbootlearn.exception写一个抛出异常的调用类GraceException.java

package com.ql.springbootlearn.exception;

/**
 * 优雅的处理异常,进行调用
 */
public class GraceException {
    public static void display(String errMsg) {
        throw new MyCustomException(errMsg);
    }
}

然后,在前面的用户信息拦截器UserInfoInterceptor.java里调用抛出异常

package com.ql.springbootlearn.controller.interceptor;

import com.ql.springbootlearn.exception.GraceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.thymeleaf.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Slf4j
public class UserInfoInterceptor implements HandlerInterceptor {
    /**
     * 拦截请求,访问Controller之前
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String userId = request.getHeader("userId");
        String userToken = request.getHeader("userToken");
        if(StringUtils.isEmpty(userId) || StringUtils.isEmpty(userToken)){
            log.error("用户校验不通过,信息不完整!");
            GraceException.display("用户校验不通过,信息不完整!");
            return false;
        }
        //假设真实的用户id是1001,用户token是abcxyz
        if(!userId.equalsIgnoreCase("1001") ||
            !userToken.equalsIgnoreCase("abcxyz")){
            log.error("用户权限不通过!");
            GraceException.display("用户权限不通过!");
            return false;
        }
        /**
         * false: 请求被拦截
         * true: 请求放行,可以继续访问后面的Controller
         */
        return true;
    }

    /**
     * 请求访问到Controller之后,渲染视图之前
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    /**
     * 请求访问到Controller之后,渲染视图之后
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

再运行项目,打开postman测试
Java框架(九)--Spring Boot入门(2)_第34张图片

SpringBoot定时任务的实现

在com.ql.springbootlearn.utils包下创建MyTask定时任务演示类

package com.ql.springbootlearn.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import java.time.LocalDateTime;

@Configuration    //1.标记配置类,使得springboot容器可以扫描到
@EnableScheduling //2.开启定时任务
@Slf4j
public class MyTask {
    //3.添加一个任务,并且注明任务的运行表达式
    @Scheduled(cron = "*/5 * * * * ?")
    public void publishMsg(){
        log.warn("开始执行任务:"+ LocalDateTime.now());
    }
}

运行项目,查看控制台。
Java框架(九)--Spring Boot入门(2)_第35张图片
注意:当前定时任务为Spring自带的,只适合单体环境运行,如果是一个集群或者分布式环境就不适合该方案了。

SpringBoot异步任务的实现

在com.ql.springbootlearn.utils包下创建异步任务类

package com.ql.springbootlearn.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Component
@EnableAsync
@Slf4j
public class MyAsyncTask {
    @Async
    public void publishMsg(){
        try {
            Thread.sleep(5000);
            log.warn("异步任务处理完毕");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

然后在HelloController.java里调用

	...
    @Autowired
    private MyAsyncTask myAsyncTask;

    @GetMapping("getMyConfig")
    public Object getMyConfig(){
        myAsyncTask.publishMsg();
        log.info("这是跳过异步任务的执行");
        return myConfig;
    }

运行项目,浏览器访问http://localhost:8090/getMyConfig,查看控制台
Java框架(九)--Spring Boot入门(2)_第36张图片
注意:该方案适合单应用,若是分布式环境一般通过消息队列去处理。

你可能感兴趣的:(Java框架,java,spring,boot,开发语言)