SpringBoot Web开发

128 阅读7分钟

一 基于restful风格的CRUD接口

image.png

这里相比之前有新的注解:

  1. @RestController: 我们可以这样理解,@RestController = @Controller + @ResponseBody,所以使用了这个注解就是默认将数据以json形式传递给前端.

  2. Apixxx: 所有关于带有Api的注解等下讲解.

  3. 如果接受参数的时候不使用@RequestBody注解的话,后端无法接受到前端传递过来的json数据

二 restTemplate

后端负责开发各种各样的接口,然后供给前端调用,但是偶尔会有后端需要调用后端的接口.这是什么意思呢?比如有projectA和projectB,projectA想调用projectB中的接口,这时就需要使用testTemplate.

举个例子: projectA有CRUD接口,projectB想调用projectA的CRUD接口

1. 在projectB中新建RestTemplate对象

image.png

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;


@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

}
2. 在projectB中使用RestTemplate远程调用projectA中的CRUD接口

2.1 restTemplate.getForObject or restTemplate.getForEntity

image.png

url: projectA中对应接口的地址

getForEntity和getForObject都可以使用,getForEntity信息相对而言会多一点

2.2 restTemplate.postForObject

image.png

在使用restTemplate.postForObject相比get要多带一个参数,因为是post请求,所以要携带一个参数进去

2.3 restTemplate.deleteForObject

image.png

这里需要注意的是,delete是没有返回值的,所以不需要拿变量接受

2.4 restTemplate.exchange

2.4.1 delete

image.png

2.4.2 get

image.png

2.4.3 post

image.png

我们可以看到,exchange会更加灵活,可以适合各种请求方式,但是请注意,在post请求的时候要添加一个实体类

三 关于@Configuration和@Bean

image.png

@Configuration: 相当于创建了一个applicationContext.xml文件

@Bean注解及其方法: 相当于向SpringIOC容器注入了一个对象,id就是方法名

@Scope: 指定javaBean的作用域

四 Swagger

swagger是用来方便前后端接口文档,这个可以随时修改

1. 引入依赖

image.png

<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-boot-starter</artifactId>
   <version>3.0.0</version>
</dependency>
2. 在application.yml中添加对应配置

image.png

spring: 
  mvc: 
    pathmatch:
      matching_strategy: ant_path_matcher
3.新建SwaggerConfig类,并且配置

image.png

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

@Configuration
@EnableOpenApi
public class SwaggerConfig {

    @Bean
    public ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Swagger Test App Restful API")
                .description("swagger test app restful api")
                .termsOfServiceUrl("https://github.com/geekxingyun")
                .contact(new Contact("卡布奇诺", "https://xingyun.blog.csdn.net", "123456789@qq.com"))
                .version("1.0")
                .build();
    }

    @Bean
    public Docket createRestApi(ApiInfo apiInfo) {
        return new Docket(DocumentationType.OAS_30)
                .apiInfo(apiInfo)
                .groupName("SwaggerGroupOneAPI")
                .select()
                //.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
                .apis(RequestHandlerSelectors.basePackage("com.cctv.controller"))
                .paths(PathSelectors.any())
                .build();
    }
}

这里注意: 除了@Configuration和@Bean注解之外,还需要加入@EnableOpenApi注解,这里大部分代码无关紧要,最重要注意34行代码,里面有个"com.cctv.controller",这里是代表扫描到这个包

4. 关于@Apixxx讲解

@Api: 用于对类的说明

@ApiOperation: 用于对方法的说明

@ApiModelProperty: 用于对类属性的说明

Swagger访问网站: 注意自己的端口号 http://localhost:8080/swagger-ui/

4.1 相关Api注解(重点关注带有Api注解的)

image.png

image.png

4.2 Swagger显示的

image.png

image.png

image.png

五 SpringBoot整合AOP和拦截器

1. SpringBoot整合AOP

1.1 导入pom依赖

image.png

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

1.2 定义切面类

import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class LogUtil {

    // 前置通知
    @Before("execution(* com.cctv.service..*.*(..))")
    public static void before(){

        System.out.println("方法前");
    }

    // 后置通知
    @After("execution(* com.cctv.service..*.*(..))")
    public static void after(){

        System.out.println("方法后");
    }

    // 后置异常通知
    @AfterThrowing("execution(* com.cctv.service..*.*(..))")
    public static void afterException(){


        System.out.println("方法异常");
    }

    // 后置返回通知
    @AfterReturning("execution(* com.cctv.service..*.*(..))")
    public static void afterEnd(){

        System.out.println("方法返回");
    }
}

这里和之前的SSM整合AOP有点类似,就不重复了

2. SpringBoot整合拦截器

2.1 创建一个类,实现HandlerInterceptor接口

image.png

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

@Component
public class MyInterceptor implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        System.out.println("请求处理之前进行调用(Controller方法调用之前)");

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        System.out.println("请求处理之后进行调用,主要是在视图被渲染之前(Controller方法调用之后)");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("请求结束之后被调用,在DispatcherServlet渲染了对应的视图之后执行(主要是用于进行资源清理工作)");
    }
}

2.2 创建配置类,添加拦截器到Spring拦截器链中

image.png

import com.cctv.interceptor.MyInterceptor;
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 MyWebMvcConfigurator implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()). //添加拦截器
                addPathPatterns("/**"). // 拦截映射规则
                excludePathPatterns("/index"); // 设置排除的映射规则


        /*
        * 排除多个路径
        * List list = new ArrayList();
        list.add("/user/toIndex");
        list.add("/user/loginUser");
        list.add("/user/toRegister");
        list.add("/user/register");
        registry.addInterceptor(new UserIntercetor()).addPathPatterns("/**").excludePathPatterns(list);
        *
        * */

    }
}

六 SpringBoot作为单体web与freemarker

如果使用了freemaker就意味着前后端会合并在一起,这里我们需要导入一个关于freemarker依赖

1. 导入pom依赖

image.png

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
2. 在application.yml中添加配置

image.png

spring: 
  freemarker: 
    cache: false
    charset: utf-8
    suffix: .html
3. 可以通过${属性名}来获取值

image.png

image.png

image.png

这里注意,如果要使用freemarker的话,我们在controller层就得使用@Controller注解而不是@RestController注解,因为我们不需要返回json数据给前端. 还有就是如果使用了freemarker模板,那么我们的文件就要放到static目录下,这个就是SpringBoot中的约定大于配置

七 关于CORS跨域问题

浏览器最核心也是最基本的安全功能就是同源策略,同源既: 相同的协议,相同的主机,相同的端口. 跨域: 当一个请求url的协议,域名,端口三者任意一个与当前页面不同即为跨域.

image.png

那么SpingBoot该如何解决CORS跨域问题呢?

新建一个配置类实现WebMvcConfigurer接口并且配置

@Configuration
public class MyWebMvcConfigurator implements WebMvcConfigurer {
    @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/user/*");   // 映射服务器中那些http接口运行跨域访问
    //                .allowedOrigins("http://localhost:8081")     // 配置哪些来源有权限跨域
    //                .allowedMethods("GET","POST","DELETE","PUT");   // 配置运行跨域访问的请求方法
        }
}

这样就解决了CORS跨域问题了

八 SpringBoot中的json

SpringBoot提供了与三个JSON映射库: Gson Jackson JSON-B,我们默认使用Jackson

这里介绍关于Json的几个注解

@JsonIgnore: 隐藏属性. 如果不想将某一个属性序列化,可以使用这个注解

@JsonFormat(pattern="yyyy-MM-dd hh:mm:ss"): 用于进行日期格式化

@JsonInclude(JsonInclude.Include.NON_NULL): 如果一个属性有值的时候就序列化,没有值就不序列化

@JsonProperty: 我们的javaBean对象里面的属性名字可能和前端传递过来的属性名字不一样,那么需要可以使用这个来映射,也就是前端传递过来的是什么,这个注解里面就写个别名

九 SpringBoot和servlet整合

1. servlet容器

SpringBoot包含了对嵌入式Tomcat,Jetty和Undertow服务器的支持,默认使用Tomcat,我们也可以切换

1.1 排除Tomcat依赖

image.png

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
   <exclusions>
      <exclusion>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-tomcat</artifactId>
      </exclusion>
   </exclusions>
</dependency>

1.2 导入对应的依赖

Jetty:

image.png

<dependency>
   <artifactId>spring-boot-starter-jetty</artifactId>
   <groupId>org.springframework.boot</groupId>
</dependency>

Undertow:

image.png

<dependency>
   <artifactId>spring-boot-starter-undertow</artifactId>
   <groupId>org.springframework.boot</groupId>
</dependency>
2. listener,filter,自定义servlet
2.1 通过@WebServlet,@WebListener,@WebFilter注解

@WebServlet:

image.png

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "HelloServlet", urlPatterns = "/index")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //super.doGet(req, resp);
        System.out.println("hello get");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //super.doPost(req, resp);
        System.out.println("hello post");
    }
}

name: 自定义servlet的类名

urlPattern: 路由

@WebFilter:

image.png

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter(urlPatterns = "/*")
public class HelloFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException, ServletException, IOException {
        System.out.println("HelloFilter");
        filterChain.doFilter(servletRequest,servletResponse);

    }
}

@WebListener:

image.png

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class ContextLoaderListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("ServletContext对象呗创建了。。。");
    }
}

不管是哪一个,做通过@Webxxx注解之后,我们还必须在启动类中加入一个@ServletComponentScan注解

image.png

2.2 @Configuration+@Bean

image.png

import com.cctv.servlet.ContextLoaderListener;
import com.cctv.servlet.HelloFilter;
import com.cctv.servlet.HelloServlet;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyWebMvcConfiguration {
    @Bean
    public ServletRegistrationBean myServlet(){
        // 声明一个servlet注册器Bean
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
        // 设置相应的servlet
        servletRegistrationBean.setServlet(new HelloServlet());
        // 设置名字
        servletRegistrationBean.setName("HelloServlet");
        // 添加映射规则
        servletRegistrationBean.addUrlMappings("/HelloServlet");
        return servletRegistrationBean;

    }

    @Bean
    public FilterRegistrationBean<HelloFilter> getFilter() {
        //通过FilterRegistrationBean实例设置优先级可以生效
        FilterRegistrationBean<HelloFilter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new HelloFilter());//注册自定义过滤器
        bean.setName("flilter1");//过滤器名称
        bean.addUrlPatterns("/*");//过滤所有路径
        bean.setOrder(1);//优先级,最顶级
        // 忽略过滤格式
        bean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*,");
        return bean;
    }

    @Bean
    public ServletListenerRegistrationBean getListener() {
        ServletListenerRegistrationBean servletListenerRegistrationBean=new ServletListenerRegistrationBean(new ContextLoaderListener());
        return servletListenerRegistrationBean;
    }

}

十 将一个SpringBoot project打包成war包

众所周知,SpringBoot默认将SpringBoot project打包成jar包,但是不可避免有的时候需要将SpringBoot project打包成war包,这里就来教一教大家如何打包成war包

1. 在pom依赖文件中修改打包成war包

image.png

  1. 让tomcat相关的依赖不参与打包部署,因为外置tomcat服务器已经有这些jar包

image.png

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-tomcat</artifactId>
   <scope>provided</scope>
</dependency>
  1. 在启动类添加一个类

image.png

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

public class TomcatStartSpringBoot extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(SpringbootDemoApplication.class);
    }
}