第十二章 微服务核心(一)

一、Spring Boot

1.1 SpringBoot 构建方式
1.1.1 通过官网自动生成

进入官网:https://spring.io/,点击 Projects --> Spring Framework;

拖动滚动条到中间位置,点击 Spring Initializr 或者直接通过 https://start.spring.io/构建。

在线生成 SpringBoot 项目,然后解压直接导入。

1.1.2 IDE 在线模板生成

File --> New --> Project --> Spring Initializr

1.1.3 IDE 通过 Maven 项目构建
2.1.1 创建 Maven 项目
2.1.2 添加依赖
XML 复制代码
	<!-- 1.添加SpringBoot的依赖 -->
    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.3.2.RELEASE</version>
    </parent>

    <dependencies>
        <!-- 2.添加SpringMVC的支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
2.1.3 创建启动类
java 复制代码
/**
 * SpringBoot 项目的启动类
 */
@SpringBootApplication
public class AppStart {
    public static void main(String[] args) {
        SpringApplication.run(AppStart.class, args);
    }
}
2.1.4 启动程序

执行主方法(main)即可。

1.2 SpringBoot 中的常规配置
1.2.1 入口类和相关注解
java 复制代码
@SpringBootApplication
public class SpringMybatisGenertorApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringMybatisGenertorApplication.class, args);
    }

}
java 复制代码
@Target({ElementType.TYPE}) // 注解可以写在哪些地方
@Retention(RetentionPolicy.RUNTIME) // 该注解的作用域  RESOURCES CLASS RUNTIME
@Documented // 该注解会被API抽取
@Inherited  // 可继承
// 以上四个是Java中提供的元注解
@SpringBootConfiguration // 本质上就是一个Configuration注解
@EnableAutoConfiguration // 自动装配的注解
@ComponentScan( // 扫描 会自动扫描 @SpringBootApplication所在的类的同级包(com.gupaoedu)以及子包中的Bean,所有一般我们建议将入口类放置在 groupId+artifcatID的组合包下
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
1.2.2 常规配置
  • 默认属性
java 复制代码
  server.port=8082
  server.servlet.context-path=/springboot
  • 自定义属性
java 复制代码
  user.userName=admin
  user.realName=零一
  user.address=湖南长沙
java 复制代码
  @RestController
  public class HelloController {
  
      @Value(value = "${user.userName}")
      private String userName;
      @Value(value = "${user.realName}")
      private String realName;
      @Value(value = "${user.address}")
      private String address;
  
      @RequestMapping("/hello")
      public String hello() {
          System.out.println("Hello ..." + userName + "  " + realName + "  " + address);
          return "Hello ...";
      }
  }

乱码问题:File --> Setting --> Editor --> File Encodings

java 复制代码
server.tomcat.uri-encoding=UTF-8
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true
spring.messages.encoding=UTF-8
  • 类型安全配置
XML 复制代码
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-configuration-processor</artifactId>
      <optional>true</optional>
  </dependency>
java 复制代码
  package com.gupaoedu.bean;
  import org.springframework.boot.context.properties.ConfigurationProperties;
  import org.springframework.stereotype.Component;
  
  @Component
  // 属性文件中的属性和User对象中的成员变量映射
  @ConfigurationProperties(prefix = "user")
  public class User {
  
      private String username;
  
      private Integer age;
  
      private String address;
  
  
      public String getUsername() {
          return username;
      }
  
      public void setUsername(String username) {
          this.username = username;
      }
  
      public Integer getAge() {
          return age;
      }
  
      public void setAge(Integer age) {
          this.age = age;
      }
  
      public String getAddress() {
          return address;
      }
  
      public void setAddress(String address) {
          this.address = address;
      }
  
      @Override
      public String toString() {
          return "User{" +
                  "username='" + username + '\'' +
                  ", age=" + age +
                  ", address='" + address + '\'' +
                  '}';
      }
  }
1.2.3 Logback 日志
java 复制代码
# logback的配置
logging.file=d:/log.log
logging.level.org.springframework.web=DEBUG
1.2.4 Profile

命名规则 application-xxx.properties
spring.profiles.active=xxx # 指定对应的环境

1.3 SpringBoot 中的静态资源
1.3.1 static 目录

SpringBoot 默认的存放静态资源的目录

1.3.2 webapp 目录

在 resources 同级目录下创建一个 webapp 目录,该目录的类型必须是 <u>ResourcesRoot</u>

1.3.3 自定义静态资源路径

自定义目录后,创建对应的相关资源,然后在属性文件中去覆盖静态资源的路径配置即可。

表示所有的访问都经过静态资源路径

spring.webflux.static-path-pattern=/**

覆盖默认的配置,所有需要将默认的 static public 等这些路径将不能作为静态资源的访问

spring.resources.static-locations=classpath:/META-INF/resources/,clas
spath:/resources/,classpath:/static/,classpath:/custom

1.4 SpringBoot 自动装配
1.4.1 @EnableAutoConfiguration
java 复制代码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

通过@EnableAutoConfiguration 注解发现。其本身就是一个组合注解,有一个注解我们必须要弄清楚@Import 注解。

1.4.2 @Import

在 Spring 中我们将类型交给 SpringIoC 管理的方式有哪些?

java 复制代码
> 1.基于xml配置文件<bean>
>
> 2.基于xml配置文件@Component
>
> 3.基于Java配置类【@Configuration】 @Bean
>
> 4.基于Java配置类+@ComponentScan+@Component
>
> 5.FactoryBean接口【getObject()】
>
> 6.@Import注解

第一种使用方式
静态使用方式

java 复制代码
@Configuration
@Import(UserService.class)
public class JavaConfig {

    /*@Bean
    public UserService getUserSerivce(){
        return new UserService();
    }*/
}

在@Import 注解中直接指定要添加的类型。
缺点:直接在@Import 中写死要注入的类型,不太灵活。
第二种使用方式
ImportSelector 接口

java 复制代码
public class GpImportSelector implements ImportSelector {
    /**
     *  动态获取IoC要加载的类型
     * @param annotationMetadata 注解的元数据
     * @return
     *     IoC要加载的类型的数组
     */
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // 根据不同的业务逻辑 实现动态添加IoC加载的类型
        /*if (){

        }*/
        return new String[]{LoggerService.class.getName(),CacheService.class.getName()};
    }
}
java 复制代码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(GpImportSelector.class)
public @interface EnableGpImport {
}


import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

@EnableGpImport
public class ImportMain {

    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(ImportMain.class);
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        for (String beanName : beanDefinitionNames){
            System.out.println(beanName);
        }
    }
}

是将@Import 注解中添加的 ImportSelector 的实现类中的 selectImports 这个方法返回的字符串数组加载到 IoC 容器中。
第三种实现方式
实现 ImportBeanDefinitionRegistrar 接口,其实和第二种方式很类似,都是在源码设计层面用的比较多。

java 复制代码
public class GpImportBeanDefinition implements ImportBeanDefinitionRegistrar {
    /**
     *  提供了一个beanDefinition的注册器,我直接把需要IoC加载的类型注册到容器中去
     * @param annotationMetadata
     * @param beanDefinitionRegistry beanDefinition的注册器
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
        // 将我们需要添加的类型统一封装为RootBeanDefinition对象
        RootBeanDefinition cache = new RootBeanDefinition(CacheService.class);
        beanDefinitionRegistry.registerBeanDefinition("cache",cache);
        RootBeanDefinition logger = new RootBeanDefinition(LoggerService.class);
        beanDefinitionRegistry.registerBeanDefinition("logger",logger);
    }
}
java 复制代码
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

@EnableGpImport
public class ImportMain {

    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(ImportMain.class);
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        for (String beanName : beanDefinitionNames){
            System.out.println(beanName);
        }
    }
}
1.4.3 自动装配的原理
  1. 在 SpringBoot 项目启动的时候,会加载 SpringBootApplication 这个注解。
  2. 会解析@EnableAutoConfiguration 注解。
  3. 与之对应的解析@Import 注解。
  4. 执行 ImportSelector 接口的的实现。
  5. 加载 META-INF/spring-autoconfigure-metadata.properties 中的注解元数据信息。
  6. 加载 META-INF/spring.factories 各种类路径【第三方扩展也同样的会加载对应的文件 SPI 扩展机制】。
1.5 SpringBoot 整合 Servlet
1.5.1 第一种方式
1. 添加自定义的 Servlet
java 复制代码
package com.gupaoedu.servlet;

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;
import java.io.PrintWriter;

@WebServlet(name = "FirstServlet",urlPatterns = "/first")
public class FirstServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("FirstServlet running ... ");
        PrintWriter out = resp.getWriter();
        out.write("success ... ");
        out.flush();
        out.close();
    }
}
2. 在启动类中添加扫描注解
java 复制代码
package com.gupaoedu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
// 在SpringBoot启动的时候会扫描@WebServlet注解
@ServletComponentScan()
public class GpSpringbootDemo05Application {

    public static void main(String[] args) {
        SpringApplication.run(GpSpringbootDemo05Application.class, args);
    }

}
1.5.2 第二种方式
1. 创建自定义的 Servlet,不需要添加@WebServlet
java 复制代码
package com.gupaoedu.servlet;

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

public class SecondServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("SecondServlet running ... ");
        PrintWriter out = resp.getWriter();
        out.write("success ... ");
        out.flush();
        out.close();
    }
}
2. 在启动类中显示在注册
java 复制代码
package com.gupaoedu;

import com.gupaoedu.filter.SecondFilter;
import com.gupaoedu.listener.SecondListener;
import com.gupaoedu.servlet.SecondServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
// 在SpringBoot启动的时候会扫描@WebServlet注解
@ServletComponentScan()
public class GpSpringbootDemo05Application {

    public static void main(String[] args) {
        SpringApplication.run(GpSpringbootDemo05Application.class, args);
    }

    @Bean
    public ServletRegistrationBean getRegistrationBean(){
        // 将要添加的Servlet封装为一个ServletRegistrationBean对象
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(new SecondServlet());
        // 设置映射信息
        registrationBean.addUrlMappings("/second");
        return registrationBean;
    }
}
1.6 SpringBoot 整合 Filter
1.6.1 第一种方式
1. 直接在过滤器中添加@WebFilter 注解
java 复制代码
package com.gupaoedu.filter;

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

@WebFilter(urlPatterns = "/first")
public class FirstFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("----init----");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("________First过滤器执行之前_________");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("________First过滤器执行之后_________");
    }

    @Override
    public void destroy() {
        System.out.println("****destroy****");
    }
}
2. 在启动器中添加@ServletCompoenentScan
java 复制代码
package com.gupaoedu;

import com.gupaoedu.filter.SecondFilter;
import com.gupaoedu.listener.SecondListener;
import com.gupaoedu.servlet.SecondServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
// 在SpringBoot启动的时候会扫描@WebServlet注解
@ServletComponentScan()
public class GpSpringbootDemo05Application {

    public static void main(String[] args) {
        SpringApplication.run(GpSpringbootDemo05Application.class, args);
    }
}
1.6.2 第二种方式
1. 创建自定义的过滤器,不需要添加@WebFilter 注解。
java 复制代码
package com.gupaoedu.filter;

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

public class SecondFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("--second--init----");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("________Second过滤器执行之前_________");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("________Second过滤器执行之后_________");
    }

    @Override
    public void destroy() {
        System.out.println("****destroy****");
    }
}
2. 在启动类中显示的注册
java 复制代码
package com.gupaoedu;

import com.gupaoedu.filter.SecondFilter;
import com.gupaoedu.listener.SecondListener;
import com.gupaoedu.servlet.SecondServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
// 在SpringBoot启动的时候会扫描@WebServlet注解
@ServletComponentScan()
public class GpSpringbootDemo05Application {

    public static void main(String[] args) {
        SpringApplication.run(GpSpringbootDemo05Application.class, args);
    }

    @Bean
    public FilterRegistrationBean getRegistractionBean(){
        FilterRegistrationBean bean = new FilterRegistrationBean(new SecondFilter());
        bean.addUrlPatterns("/second");
        return bean;
    }
}
1.7 SpringBoot 整合 Listener
1.7.1 第一种方式
1. 创建自定义的 Listener
java 复制代码
package com.gupaoedu.listener;

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

@WebListener
public class FirstListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("FirstListener : 初始化了....");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("FirstListener : 销毁了....");
    }
}
2. 添加扫描注解
java 复制代码
package com.gupaoedu;

import com.gupaoedu.filter.SecondFilter;
import com.gupaoedu.listener.SecondListener;
import com.gupaoedu.servlet.SecondServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
// 在SpringBoot启动的时候会扫描@WebServlet注解
@ServletComponentScan()
public class GpSpringbootDemo05Application {

    public static void main(String[] args) {
        SpringApplication.run(GpSpringbootDemo05Application.class, args);
    }
}
1.7.2 第二种方式
1. 创建自定义 Listener
java 复制代码
package com.gupaoedu.listener;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class SecondListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("SecondListener : 初始化了....");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("SecondListener : 销毁了....");
    }
}
2. 显示的在启动类中注册
java 复制代码
package com.gupaoedu;

import com.gupaoedu.filter.SecondFilter;
import com.gupaoedu.listener.SecondListener;
import com.gupaoedu.servlet.SecondServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
// 在SpringBoot启动的时候会扫描@WebServlet注解
@ServletComponentScan()
public class GpSpringbootDemo05Application {

    public static void main(String[] args) {
        SpringApplication.run(GpSpringbootDemo05Application.class, args);
    }
        
    @Bean
    public ServletListenerRegistrationBean getListenerRegistrationBean(){
       ServletListenerRegistrationBean bean = new ServletListenerRegistrationBean(new SecondListener());
       return bean;
    }
}
1.8 SpringBoot 整合 Freemarker
1.8.1 添加对应的依赖
XML 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
1.8.2 添加一个自定义的控制器
java 复制代码
package com.gupaoedu.controller;

import com.gupaoedu.bean.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.ArrayList;
import java.util.List;

@Controller
public class UserController {

    @RequestMapping("/showUser")
    public String showUser(Model model){
        List<User> list = new ArrayList<>();
        list.add(new User(1,"zhangsan",22));
        list.add(new User(2,"lisi",23));
        list.add(new User(3,"wangwu",24));
        model.addAttribute("list",list);
        return "user";
    }
}
1.8.3 属性文件配置

spring.freemarker.suffix=.ftl

1.8.4 ftl 模板页面

是一个 ftl 文件

html 复制代码
<html>
    <head>
        <title>用户信息</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <table border="1" align="center" width="50%">
            <tr>
                <th>ID</th>
                <th>姓名</th>
                <th>年龄</th>
            </tr>
            <#list list as user>
                <tr>
                    <td>${user.id}</td>
                    <td>${user.userName}</td>
                    <td>${user.age}</td>
                </tr>
            </#list>
        </table>
    </body>
</html>
1.9 SpringBoot 整合 Thymeleaf
1.9.1 添加相关的依赖
XML 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
1.9.2 创建自定义的控制器
java 复制代码
package com.gupaoedu.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class UserController {

    @RequestMapping("/show")
    public String showInfo(Model model){
        model.addAttribute("msg","Thymeleaf Hello ....");
        return "index";
    }
}
1.9.3 创建对应的模板页面

Thymeleaf 的模板页面的后缀是`.html` 和我们讲的 html 页面的后缀是一样,但可以写标签。

html 复制代码
<!DOCTYPE html>
<html lang="en"  xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>Thymeleaf整合</h1>
    <hr>
    <span th:text="${msg}"></span>
</body>
</html>
1.10 SpringBoot 实现热部署操作
1.10.1 打开配置


1.10.2 按下快捷键【ctrl+shift+alt+'/'】


1.10.3 添加 spring-boot-devtools 依赖
XML 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
</dependency>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <fork>true</fork>
            </configuration>
        </plugin>
    </plugins>
</build>
1.11 SpringBoot 中的异常处理
1.11.1 自定义错误页面

SpringBoot 默认的处理异常的机制:SpringBoot 默认的已经提供了一套处理异常的机制。一旦程序中出现了异常 SpringBoot 会像/error 的 url 发送请求。在 springBoot 中提供了一个叫 BasicExceptionController 来处理/error 请求,然后跳转到默认显示异常的页面来展示异常信息。

我们只需要在 resources/templates 中添加一个 error.html 页面即可。

1.11.2 @ExceptionHandler 处理

针对特定的异常处理。
控制器:

java 复制代码
package com.gupaoedu.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import javax.validation.constraints.Null;

@Controller
public class UserController {

    @RequestMapping("/show1")
    public String showInfo1(){
        String msg = null;
        msg.length(); // NullPointerException
        return "success";
    }

    /**
     * 如果当前类中出现了NullPointerException异常就会跳转到本方法对应的view中
     * @return
     */
    @ExceptionHandler(value = {NullPointerException.class})
    public ModelAndView nullPointerExceptionHandler(Exception e){
        ModelAndView view = new ModelAndView();
        view.addObject("error",e.toString());
        view.setViewName("error1");
        return view;
    }

    /**
     * 如果当前类中出现了ArithmeticException异常就会跳转到本方法对应的view中
     * @return
     */
    @ExceptionHandler(value = {ArithmeticException.class})
    public ModelAndView arithmeticExceptionHandler(Exception e){
        ModelAndView view = new ModelAndView();
        view.addObject("error",e.toString());
        view.setViewName("error2");
        return view;
    }

    @RequestMapping("/show2")
    public String showInfo2(){
        int i = 0;
        int b = 100;
        System.out.println(b/i); // ArithmeicExpetion
        return "success";
    }

}

异常处理代码和业务代码耦合性比较强。

1.11.3 @ControllerAdvice 处理

实现业务代码和系统异常处理代码解耦。

java 复制代码
package com.gupaoedu.handler;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

@ControllerAdvice
public class GlobalException {
    /**
     * 如果当前类中出现了NullPointerException异常就会跳转到本方法对应的view中
     * @return
     */
    @ExceptionHandler(value = {NullPointerException.class})
    public ModelAndView nullPointerExceptionHandler(Exception e){
        ModelAndView view = new ModelAndView();
        view.addObject("error",e.toString());
        view.setViewName("error1");
        return view;
    }

    /**
     * 如果当前类中出现了ArithmeticException异常就会跳转到本方法对应的view中
     * @return
     */
    @ExceptionHandler(value = {ArithmeticException.class})
    public ModelAndView arithmeticExceptionHandler(Exception e){
        ModelAndView view = new ModelAndView();
        view.addObject("error",e.toString());
        view.setViewName("error2");
        return view;
    }
}
1.11.4 SimpleMappingExceptionResolver 处理

通过系统提供的异常映射处理实现

java 复制代码
package com.gupaoedu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import  java.util.Properties;

@SpringBootApplication
public class GpSpringbootDemo08ThymeleafApplication {

    public static void main(String[] args) {
        SpringApplication.run(GpSpringbootDemo08ThymeleafApplication.class, args);
    }

    /**
     * 异常信息和对应的 处理地址的 映射
     * @return
     */
    @Bean
    public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){

        SimpleMappingExceptionResolver mapping = new SimpleMappingExceptionResolver();
        Properties mappings = new Properties();
        mappings.setProperty("java.lang.NullPointerException","error1");
        mappings.setProperty("java.lang.ArithmeticException","error2");
        mapping.setExceptionMappings(mappings);
        return mapping;
    }
}
1.11.5 自定义 HandlerExceptionResolver
java 复制代码
package com.gupaoedu.handler;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
    /**
     * 自定义的全局异常
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     * @param e
     * @return
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest
            , HttpServletResponse httpServletResponse
            , Object o, Exception e) {
        System.out.println("全局的自定义异常处理触发了....");
        ModelAndView mv = new ModelAndView();
        if(e instanceof  NullPointerException){
            mv.setViewName("error1");
            mv.addObject("error","空指针异常");
        }else if(e instanceof  ArithmeticException){
            mv.setViewName("error2");
            mv.addObject("error","算数异常");
        }
        return mv;
    }
}
1.12 SpringBoot 中的单元测试
1.12.1 添加依赖
XML 复制代码
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-test</artifactId>
     <scope>test</scope>
</dependency>
1.12.2 单元测试


1.13 SpringBoot 整合 MyBatis

整合 MyBatis 同时结合 SpringMVC+Thymeleaf 完成 CRUD 操作。

1.13.1 添加依赖
XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.gupaoedu</groupId>
    <artifactId>gp_springboot_mybatis_demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 配置依赖的父类 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.14</version>
        </dependency>
    </dependencies>

</project>
1.13.2 配置文件
java 复制代码
# jdbc的相关配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456

# 连接池
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

## mybatis的package别名
mybatis.type-aliases-package=com.gupaoedu.pojo

# 指定MyBatis的映射文件的路径
mybatis.mapper-locations=classpath:mapper/*.xml
1.13.3 启动器
java 复制代码
package com.gupaoedu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class StartApp {

    public static void main(String[] args) {
        SpringApplication.run(StartApp.class,args);
    }
}
1.13.4 数据库表结构
sql 复制代码
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT, 
`name` varchar(255) DEFAULT NULL, 
`age` int(11) DEFAULT NULL, PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1.13.5 创建对应的 Pojo 对象
java 复制代码
package com.gupaoedu.pojo;

public class User {

    private Integer id;

    private String name;

    private Integer age;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
1.13.6 mapper 接口
java 复制代码
package com.gupaoedu.mapper;

import com.gupaoedu.pojo.User;
import java.util.List;

public interface UserMapper {

    public List<User> query(User user);

    public Integer addUser(User user);

    /**
     * 根据id查询用户信息
     * @param id
     * @return
     */
    public User queryById(Integer id);

    public Integer deleteUserById(Integer id);

    public Integer updateUser(User user);
}
1.13.7 mapper 映射文件

文件地址:src/main/resources/mapper/UserMapper.xml

XML 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gupaoedu.mapper.UserMapper">
    <select id="query" resultType="User">
        select * from users
    </select>

    <insert id="addUser" parameterType="User">
        INSERT INTO users (name,age)VALUES(#{name},#{age})
    </insert>

    <select id="queryById" resultType="User" >
        select * from users where id = #{id}
    </select>

    <update id="updateUser" parameterType="User">
        update users set name=#{name},age=#{age} where id =#{id}
    </update>

    <delete id="deleteUserById" >
        delete from users where id = #{id}
    </delete>
</mapper>
1.13.8 Service 接口
java 复制代码
package com.gupaoedu.service;

import com.gupaoedu.pojo.User;
import java.util.List;

public interface IUserService {

    public List<User> query(User user);

    public Integer addUser(User user);

    /**
     * 根据id查询用户信息
     * @param id
     * @return
     */
    public User queryById(Integer id);

    public Integer updateUser(User user);

    public Integer deleteUserById(Integer id);
}
1.13.9 Service 实现类
java 复制代码
package com.gupaoedu.service.impl;

import com.gupaoedu.mapper.UserMapper;
import com.gupaoedu.pojo.User;
import com.gupaoedu.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;

@Service
@Transactional
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper mapper;
    @Override
    public List<User> query(User user) {
        return mapper.query(user);
    }

    @Override
    public Integer addUser(User user) {
        return mapper.addUser(user);
    }

    @Override
    public User queryById(Integer id) {
        return mapper.queryById(id);
    }

    @Override
    public Integer updateUser(User user) {
        return mapper.updateUser(user);
    }

    @Override
    public Integer deleteUserById(Integer id) {
        return mapper.deleteUserById(id);
    }
}
1.13.10 controller
java 复制代码
package com.gupaoedu.controller;

import com.gupaoedu.pojo.User;
import com.gupaoedu.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@Controller
public class UserController {

    @Autowired
    private IUserService service;

    /**
     * 基础页面的请求
     * @param page
     * @return
     */
    @RequestMapping("/{page}")
    public String showPage(@PathVariable String page){
        return page;
    }

    @RequestMapping("/user/query")
    public String query(Model model){
        model.addAttribute("list",service.query(null));
        return "user";
    }
    @RequestMapping("/user/save")
    public String addUser(User user){
       service.addUser(user);
       return "redirect:/user/query";
    }
    @RequestMapping("/user/updateInfo")
    public String updateInfo(Integer id,Model model){
        User user = service.queryById(id);
        model.addAttribute("user",user);
        return "updateUser";
    }

    @RequestMapping("/user/deleteUser")
    public String deleteUser(Integer id){
        service.deleteUserById(id);
        return "redirect:/user/query";
    }

    @RequestMapping("/user/update")
    public String updateUser(User user){
        service.updateUser(user);
        return "redirect:/user/query";
    }
}
1.13.11 启动类添加 Mapper 扫描路径
java 复制代码
package com.gupaoedu;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.gupaoedu.mapper") // 用户扫描Mapper接口
public class StartApp {

    public static void main(String[] args) {
        SpringApplication.run(StartApp.class,args);
    }
}
1.13.12 用户信息查询

控制器

java 复制代码
@Controller
public class UserController {

    @Autowired
    private IUserService service;

    @RequestMapping("/user/query")
    public String query(Model model){
        model.addAttribute("list",service.query(null));
        return "user";
    }
}

模板页面(src\main\resources\templates\user.html)

html 复制代码
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>用户信息</title>
</head>
<body>
    <h1>用户管理</h1>
    <table border="1" style="width: 300px">
        <tr>
            <th>用户ID</th>
            <th>用户姓名</th>
            <th>用户年龄</th>
        </tr>
        <tr th:each="user:${list}">
            <td th:text="${user.id}"></td>
            <td th:text="${user.name}"></td>
            <td th:text="${user.age}"></td>
        </tr>
    </table>
</body>
</html>
1.13.13 用户信息添加

mapper 接口

java 复制代码
public interface UserMapper {

    public List<User> query(User user);

    public Integer addUser(User user);
}

mapper 映射文件

java 复制代码
<insert id="addUser" parameterType="User">
    INSERT INTO users (name,age)VALUES(#{name},#{age})
</insert>

service接口

public interface IUserService {

    public List<User> query(User user);

    public Integer addUser(User user);
}

service 实现类

java 复制代码
@Service
@Transactional
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper mapper;
    @Override
    public List<User> query(User user) {
        return mapper.query(user);
    }

    @Override
    public Integer addUser(User user) {
        return mapper.addUser(user);
    }
}

控制器

java 复制代码
@Controller
public class UserController {

    @Autowired
    private IUserService service;

    @RequestMapping("/user/query")
    public String query(Model model){
        model.addAttribute("list",service.query(null));
        return "user";
    }
    @RequestMapping("/user/save")
    public String addUser(User user){
       service.addUser(user);
       return "redirect:/user/query";
    }
}

页面(src\main\resources\templates\addUser.html)

html 复制代码
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>用户信息</title>
    </head>
    <body>
        <h1>添加用户</h1>
        <form th:action="@{/user/save}" method="post">
            <label>姓名:</label><input type="text" name="name"><br>
            <label>年龄:</label><input type="text" name="age"><br>
            <input type="submit" value="提交">
        </form>

    </body>
</html>

基础跳转请求

java 复制代码
/**
     * 基础页面的请求
     * @param page
     * @return
     */
@RequestMapping("/{page}")
public String showPage(@PathVariable String page){
    return page;
}
1.13.14 用户信息修改

页面添加修改按钮(src\main\resources\templates\user.html)

html 复制代码
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>用户信息</title>
</head>
<body>
    <h1>用户管理</h1>
    <table border="1" style="width: 300px">
        <tr>
            <th>用户ID</th>
            <th>用户姓名</th>
            <th>用户年龄</th>
            <th>操作</th>
        </tr>
        <tr th:each="user:${list}">
            <td th:text="${user.id}"></td>
            <td th:text="${user.name}"></td>
            <td th:text="${user.age}"></td>
            <td>
                <a th:href="@{/user/updateInfo(id=${user.id})}">修改</a>
            </td>
        </tr>
    </table>
</body>
</html>

mapper 接口

java 复制代码
package com.gupaoedu.mapper;

import com.gupaoedu.pojo.User;
import java.util.List;

public interface UserMapper {

    public List<User> query(User user);

    public Integer addUser(User user);

    /**
     * 根据id查询用户信息
     * @param id
     * @return
     */
    public User queryById(Integer id);

    public Integer updateUser(User user);
}

mapper 映射文件

XML 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gupaoedu.mapper.UserMapper">
    <select id="query" resultType="User">
        select * from users
    </select>

    <insert id="addUser" parameterType="User">
        INSERT INTO users (name,age)VALUES(#{name},#{age})
    </insert>

    <select id="queryById" resultType="User" >
        select * from users where id = #{id}
    </select>

    <update id="updateUser" parameterType="User">
        update users set name=#{name},age=#{age} where id =#{id}
    </update>
</mapper>

控制器

java 复制代码
package com.gupaoedu.controller;

import com.gupaoedu.pojo.User;
import com.gupaoedu.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@Controller
public class UserController {

    @Autowired
    private IUserService service;

    /**
     * 基础页面的请求
     * @param page
     * @return
     */
    @RequestMapping("/{page}")
    public String showPage(@PathVariable String page){
        return page;
    }

    @RequestMapping("/user/query")
    public String query(Model model){
        model.addAttribute("list",service.query(null));
        return "user";
    }
    @RequestMapping("/user/save")
    public String addUser(User user){
       service.addUser(user);
       return "redirect:/user/query";
    }
    @RequestMapping("/user/updateInfo")
    public String updateInfo(Integer id,Model model){
        User user = service.queryById(id);
        model.addAttribute("user",user);
        return "updateUser";
    }

    @RequestMapping("/user/update")
    public String updateUser(User user){
        service.updateUser(user);
        return "redirect:/user/query";
    }
}

跳转到修改界面(src\main\resources\templates\addUser.html)

html 复制代码
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>用户信息</title>
    </head>
    <body>
        <h1>更新用户</h1>
        <form th:action="@{/user/update}" method="post">
            <input type="hidden" name="id" th:value="${user.id}">
            <label>姓名:</label><input type="text" name="name" th:value="${user.name}"><br>
            <label>年龄:</label><input type="text" name="age" th:value="${user.age}"><br>
            <input type="submit" value="提交">
        </form>

    </body>
</html>
1.13. 15 用户信息删除

添加删除按钮(src\main\resources\templates\user.html)

html 复制代码
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>用户信息</title>
</head>
<body>
    <h1>用户管理</h1>
    <table border="1" style="width: 300px">
        <tr>
            <th>用户ID</th>
            <th>用户姓名</th>
            <th>用户年龄</th>
            <th>操作</th>
        </tr>
        <tr th:each="user:${list}">
            <td th:text="${user.id}"></td>
            <td th:text="${user.name}"></td>
            <td th:text="${user.age}"></td>
            <td>
                <a th:href="@{/user/updateInfo(id=${user.id})}">修改</a>

                <a th:href="@{/user/deleteUser(id=${user.id})}">删除</a>
            </td>
        </tr>
    </table>
</body>
</html>

控制器:提交删除的编号

java 复制代码
@RequestMapping("/user/deleteUser")
public String deleteUser(Integer id){
    service.deleteUserById(id);
    return "redirect:/user/query";
}
1.14 SpringBoot 整合 Shiro
1.14.1 表结构
sql 复制代码
CREATE TABLE `t_user` (
  `id` int(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(20) DEFAULT NULL,
  `password` varchar(100) DEFAULT NULL,
  `salt` varchar(100) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  `state` int(1) DEFAULT NULL,
  `last_login_time` datetime DEFAULT NULL,
  `nickname` varchar(30) DEFAULT NULL,
  `realname` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
1.14.2 添加依赖
XML 复制代码
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.3.2</version>
</dependency>
1.14.3 自定义的 realm
java 复制代码
package com.gupaoedu.realm;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

public class AuthcRealm extends AuthorizingRealm {


    /**
     * 认证的方法
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        return null;
    }

    /**
     * 授权的方法
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
}
1.14.4 Shiro 的配置类

将我们原来写在 xml 文件中的配置添加到了 Java 类中。

java 复制代码
package com.gupaoedu.config;

import com.gupaoedu.realm.AuthcRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {

    // 散列算法
    private String hashAlgorithmName = "md5";
    // 迭代次数
    private Integer hashIterations = 1024;

    /**
     * 获取凭证匹配器
     * @return
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName(hashAlgorithmName);
        matcher.setHashIterations(hashIterations);
        return matcher;
    }

    /**
     * 获取自定义的Realm
     * @return
     */
    @Bean
    public AuthcRealm authcRealm(HashedCredentialsMatcher matcher){
        AuthcRealm realm = new AuthcRealm();
        realm.setCredentialsMatcher(matcher);
        return  realm;
    }

    /**
     *  获取SecurityManager对象
     * @param realm
     * @return
     */
    @Bean
    public SecurityManager securityManager(AuthcRealm realm){
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(realm);
        return manager;
    }

    /**
     * 注册ShiroFilterFactoryBean
     * @param manager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager manager){
        ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
        filter.setSecurityManager(manager);
        filter.setLoginUrl("/login.do");
        filter.setSuccessUrl("/success.html");
        filter.setUnauthorizedUrl("/refuse.html");
        // 设置过滤器链
        Map<String,String> map = new HashMap<>();
        map.put("/css/*","anon");
        map.put("/js/**","anon");
        map.put("/img/**","anon");
        map.put("/js/**","anon");
        map.put("/login","anon");
        map.put("/login.do","authc");
        map.put("/**","authc");
        filter.setFilterChainDefinitionMap(map);
        return filter;
    }
}
1.14.5 认证配置
java 复制代码
package com.gupaoedu.realm;

import com.gupaoedu.pojo.User;
import com.gupaoedu.service.IUserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.SimpleByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;

public class AuthcRealm extends AuthorizingRealm {

    @Autowired
    private IUserService service;

    /**
     * 认证的方法
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String userName = token.getUsername();
        System.out.println("开始认证:" + userName);
        User user = new User();
        user.setUsername(userName);
        // 根据账号认证
        List<User> list = service.query(user);
        if(list == null || list.size() != 1){
            // 账号不存在或者异常
            return  null;
        }
        user = list.get(0);
        return new SimpleAuthenticationInfo(user
                ,user.getPassword() // 密码
                ,new SimpleByteSource(user.getSalt()) // salt
                ,"authcRealm" // 自定义的Realm名称
        );
    }

    /**
     * 授权的方法
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
}
1.14.6 控制器
java 复制代码
package com.gupaoedu.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;

@Controller
public class AuthcController {

    @RequestMapping("/login.do")
    public String login(HttpServletRequest request){
        // 认证失败的异常信息
        Object obj = request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
        System.out.println("认证失败的信息:" + obj);
        return "login";
    }
    @RequestMapping("/logout.do")
    public String logout(){
        SecurityUtils.getSubject().logout();
        return "redirect:/login";
    }
}
1.14.7 登录界面
html 复制代码
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>登录管理</h1>
    <form th:action="/login.do" method="post">
        <label>账号:</label><input type="text" name="username"><br>
        <label>密码:</label><input type="password" name="password"><br>
        <input type="submit" value="提交">
    </form>
</body>
</html>
1.15 SpringBoot 整合 SpringSecurity
1.15.1 添加 SpringSecurity 的依赖即可
XML 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
1.15.2 重启访问即可跳转到对应的登录界面


> 系统启动的时候会帮我们创建一个随机的密码,账号是 user。

1.15.3 自定义登录界面

准备一个登录的 HTML 页面。

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<h2>自定义登录页面</h2>
<form action="/authentication/form" method="post">
    <table>
        <tr>
            <td>用户名:</td>
            <td><input type="text" name="username"></td>
        </tr>
        <tr>
            <td>密码:</td>
            <td><input type="password" name="password"></td>
        </tr>
        <tr>
            <td colspan="2">
                <button type="submit">登录</button>
            </td>
        </tr>
    </table>
</form>
</body>
</html>
1.15.4 自定义 SpringSecurity 的配置类
java 复制代码
package com.gupaoedu.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity // 方法SpringSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 认证的配置
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 配置自定义的账号密码
        auth.inMemoryAuthentication()
                .withUser("zhang")
                .password("{noop}123")
                .roles("USER");// 用户具有的角色
    }


    /**
     * http请求的配置
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                .loginPage("/login.html") // 指定自定义的登录界面
                .loginProcessingUrl("/login.do") // 必须和登录表单的 action一致
                .and()
                .authorizeRequests() // 定义哪些资源被保护
                .antMatchers("/login.html")
                .permitAll() // login.html可以匿名访问
                .anyRequest()
                .authenticated(); //出来登录页面其他都需要认证
        http.csrf().disable();// 禁用跨越攻击
    }
}
1.15.5 数据库认证

创建一个 service 继承 UserDetailService

java 复制代码
public interface UserService extends UserDetailsService {
}
1.15.6 service 实现中冲 load***方法
java 复制代码
package com.gupaoedu.service.impl;

import com.gupaoedu.service.UserService;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;

@Service
public class UserServiceImpl implements UserService {
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        // 模拟数据库操作 根据账号查询
        String password = "456";
        // 假设查询出来的用户的角色
        List<SimpleGrantedAuthority> list = new ArrayList<>();
        list.add(new SimpleGrantedAuthority("USER1"));
        UserDetails userDetails = new User(s,"{noop}"+password,list);
        return userDetails;
    }
}
1.15.7 在 SpringSecurity 的配置类添加配置信息
java 复制代码
package com.gupaoedu.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;

@Configuration
@EnableWebSecurity // 方法SpringSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * 认证的配置
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 配置自定义的账号密码
        /*auth.inMemoryAuthentication()
                .withUser("zhang")
                .password("{noop}123")
                .roles("USER");// 用户具有的角色*/
        // 关联自定义的认证的Service
        auth.userDetailsService(userDetailsService);
    }


    /**
     * http请求的配置
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                .loginPage("/login.html") // 指定自定义的登录界面
                .loginProcessingUrl("/login.do") // 必须和登录表单的 action一致
                .and()
                .authorizeRequests() // 定义哪些资源被保护
                .antMatchers("/login.html")
                .permitAll() // login.html可以匿名访问
                .anyRequest()
                .authenticated(); //出来登录页面其他都需要认证
        http.csrf().disable();// 禁用跨越攻击
    }
}
1.15.8 加密认证

在配置类中指定解密器。

java 复制代码
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 配置自定义的账号密码
        /*auth.inMemoryAuthentication()
                .withUser("zhang")
                .password("{noop}123")
                .roles("USER");// 用户具有的角色*/
        // 关联自定义的认证的Service
        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }
1.15.9 在 service 获取对应的加密的密文
java 复制代码
package com.gupaoedu.service.impl;

import com.gupaoedu.service.UserService;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class UserServiceImpl implements UserService {
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        // 模拟数据库操作 根据账号查询
        String password = "$2a$10$9tzTU0L5cM7e25RPo.KGnOfzUzeulD0CzOoawooYSiUlrPABkCPXG";
        // 假设查询出来的用户的角色
        List<SimpleGrantedAuthority> list = new ArrayList<>();
        list.add(new SimpleGrantedAuthority("USER1"));
        UserDetails userDetails = new User(s,password,list);
        return userDetails;
    }
}
1.16 SpringBoot 整合 Ehcache
1.16.1 添加依赖
XML 复制代码
<dependency>
    <groupId>error</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>
1.16.2 添加 Ehcache 的配置
html 复制代码
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">

    <diskStore path="java.io.tmpdir"/>
    <!--defaultCache:echcache 的默认缓存策略 -->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            maxElementsOnDisk="10000000"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </defaultCache>
    <!-- 自定义缓存策略 -->
    <cache name="users"
           maxElementsInMemory="10000"
           eternal="false"
           timeToIdleSeconds="120"
           timeToLiveSeconds="120"
           maxElementsOnDisk="10000000"
           diskExpiryThreadIntervalSeconds="120"
           memoryStoreEvictionPolicy="LRU">
        <persistence strategy="localTempSwap"/>
    </cache>
</ehcache>
1.16.3 在 application.properties 中关联 Ehcache 的配置文件
1.16.4 在需要开启换的位置通过 Cacheable 设置
1.16.5 单元测试,放开缓存
XML 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
</dependency>
java 复制代码
package com.gupaoedu.test;

import com.gupaoedu.service.IUserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
@EnableCaching// 放开缓存
public class Test01 {

    @Autowired
    private IUserService userService;

    @Test
    public void test01(){
        userService.queryById(1);
        userService.queryById(1);
    }
}
1.17 SpringBoot 整合 SpringDataRedis
1.17.1 添加相关的依赖
XML 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>
1.17.2 配置信息
XML 复制代码
spring.redis.jedis.pool.max-idle=10
spring.redis.jedis.pool.min-idle=5
spring.redis.jedis.pool.max-active=20
spring.redis.host=192.168.187.120
spring.redis.port=6379
1.17.3 Redis 的配置类
java 复制代码
package com.gupaoedu.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

@Configuration
public class RedisConfig {

    /**
     * 创建JedisPoolConfig对象
     * @return
     */
    @Bean
    @ConfigurationProperties(prefix = "spring.redis.pool")
    public JedisPoolConfig jedisPoolConfig(){
        JedisPoolConfig config = new JedisPoolConfig();
        System.out.println("默认值:" + config.getMaxIdle());
        System.out.println("默认值:" + config.getMinIdle());
        System.out.println("默认值:" + config.getMaxTotal());
        return config;
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.redis.pool")
    public JedisConnectionFactory jedisConnectionFactory(JedisPoolConfig config){
        JedisConnectionFactory factory = new JedisConnectionFactory();
        factory.setPoolConfig(config);
        return factory;
    }

    @Bean
    public RedisTemplate<String,Object> redisTemplate(JedisConnectionFactory jedisConnectionFactory){
        RedisTemplate<String,Object> template = new RedisTemplate<>();
        template.setConnectionFactory(jedisConnectionFactory);
        // 设置 key的序列号器
        template.setKeySerializer(new StringRedisSerializer());
        // 设置 value的序列化器
        template.setValueSerializer(new StringRedisSerializer());
        return template;

    }
}
1.17.4 单元测试
java 复制代码
package com.gupaoedu;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;

@RunWith(SpringRunner.class)
@SpringBootTest
public class GpSpringbootRedisDemoApplicationTests {

    @Autowired
    private RedisTemplate<String,Object> template;

    /**
     * 添加一个简单的字符串
     */
    @Test
    public void test01() {
        this.template.opsForValue().set("name","bobo");
    }

}
java 复制代码
package com.gupaoedu;

import com.gupaoedu.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.Jedis;

@RunWith(SpringRunner.class)
@SpringBootTest
public class GpSpringbootRedisDemoApplicationTests {

    @Autowired
    private RedisTemplate<String,Object> template;

    /**
     * 添加一个简单的字符串
     */
    @Test
    public void test01() {
        this.template.opsForValue().set("name","bobo");
    }

    @Test
    public void test02() {
        System.out.println(template.opsForValue().get("name"));
    }

    /**
     * 将User对象序列化为一个字符串存储
     */
    @Test
    public void test03(){
        User user = new User(1,"张三","湖南长沙");
        // 设置序列化器
        template.setValueSerializer(new JdkSerializationRedisSerializer());
        template.opsForValue().set("user",user);

    }

    /**
     * 将Redis中存储的User对象反序列化出来
     */
    @Test
    public void test04(){
        template.setValueSerializer(new JdkSerializationRedisSerializer());
        User user = (User) this.template.opsForValue().get("user");
        System.out.println(user);
    }

    /**
     * 将User对象转换为JSON对象存储
     */
    @Test
    public void test05(){
        User user = new User(2,"李四","湖南长沙");
        template.setValueSerializer(new Jackson2JsonRedisSerializer<>(User.class));
        template.opsForValue().set("userJson",user);

    }

    /**
     * 将Redis中存储的JSON数据取出转换为User对象
     */
    @Test
    public void test06(){
        template.setValueSerializer(new Jackson2JsonRedisSerializer<>(User.class));
        User user = (User) template.opsForValue().get("userJson");
        System.out.println(user);
    }

}
1.18 SpringBoot 整合 Scheduled

Scheduled 定时任务,Spring3.0 之后就提供的有。

1.18.1 添加相关的依赖
html 复制代码
<!-- 添加 Scheduled 坐标 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>5.1.7.RELEASE</version>
        </dependency>
1.18.2 创建定时任务的方法
java 复制代码
package com.gupaoedu.task;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Date;

@Component
public class MyScheduledTask {

    /**
     * 定时任务的方法
     */
    @Scheduled(cron = "0/2 * * * * ?")
    public void doSome(){
        System.out.println("定时任务执行了...." + new Date());
    }
}
1.18.3 在启动器中放开 Scheduled
java 复制代码
@SpringBootApplication
@EnableScheduling // 放开Scheduled定时任务
public class GpSpringbootScheduledDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(GpSpringbootScheduledDemoApplication.class, args);
    }

}

cron 表达式 长度 6/7 位
> Seconds Minutes Hours Day Month Week Year
>
> Seconds Minutes Hours Day Month Week
例子
>@Scheduled(cron = "0 0 1 1 1 ?")//每年一月的一号的 1:00:00 执行一次
>
>@Scheduled(cron = "0 0 1 1 1,6 ?") //一月和六月的一号的 1:00:00 执行一次
>
>@Scheduled(cron = "0 0 1 1 1,4,7,10 ?") //每个季度的第一个月的一号的 1:00:00 执行一次
>
>@Scheduled(cron = "0 0 1 1 * ?")//每月一号 1:00:00 执行一次
>
>@Scheduled(cron="0 0 1 * * *") //每天凌晨 1 点执行一次

1.19 SpringBoot 整合 Quartz
java 复制代码
| 组成                | 描述                         |
| ------------------- | ---------------------------- |
| Job--任务           | 你要做什么事?               |
| Trigger--触发器     | 你什么时候去做?             |
| Scheduler--任务调度 | 你什么时候需要去做什么事情? |
1.19.1 Quartz 基本使用
1. 依赖
XML 复制代码
<!-- Quartz 坐标 -->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.2.1</version>
</dependency>
2. 创建 Job
java 复制代码
package com.gupaoedu.Job;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;

public class MyJob implements Job {
    /**
     * 自定义的Job
     * @param jobExecutionContext
     * @throws JobExecutionException
     */
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("quartz任务执行了..." + new Date());
    }
}
3. 测试
java 复制代码
package com.gupaoedu.Job;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

public class JobMain {
    public static void main(String[] args) throws SchedulerException {
        // 1.创建Job对象
        JobDetail job = JobBuilder.newJob(MyJob.class).build();

        // 2.创建Trigger
        Trigger trigger = TriggerBuilder
                .newTrigger()
                .withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?"))
                .build();
        // 3.创建Scheduler对象
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        scheduler.scheduleJob(job,trigger);
        // 启动
        scheduler.start();
    }
}
1.19.2 SpringBoot 整合 Quartz
1. 添加对应的依赖
html 复制代码
<!-- Quartz 坐标 -->
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.2.1</version>
        <exclusions>
            <exclusion>
                <artifactId>slf4j-api</artifactId>
                <groupId>org.slf4j</groupId>
            </exclusion>
        </exclusions>
    </dependency>
    <!-- 添加 Scheduled 坐标 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
    </dependency>
    <!-- Sprng tx 坐标 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
    </dependency>
2. 创建对应的 Quartz 配置类
java 复制代码
package com.gupaoedu.config;

import com.gupaoedu.Job.MyJob;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;

@Configuration
public class QuartzConfig {

    /**
     * 创建Job对象
     * @return
     */
    @Bean
    public JobDetailFactoryBean jobDetailFactoryBean(){
        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
        // 关联 Job类
        factoryBean.setJobClass(MyJob.class);
        return factoryBean;
    }

    /**
     * 创建Trigger对象
     * @return
     */
    @Bean
    public SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
        SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
        // 关联JobDetail对象
        factoryBean.setJobDetail(jobDetailFactoryBean.getObject());
        // 设置间隔时间
        factoryBean.setRepeatInterval(2000);
        // 设置重复次数
        factoryBean.setRepeatCount(3);
        return factoryBean;
    }
    /**
     * 创建Trigger对象 Cron表达式
     * @return
     */
    @Bean
    public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
        CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
        factoryBean.setJobDetail(jobDetailFactoryBean.getObject());
        // 设置触发的时间
        factoryBean.setCronExpression("0/3 * * * * ?");
        return factoryBean;
    }

    /**
     * 创建对应的Scheduler对象
     * @param cronTriggerFactoryBean
     * @return
     */
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactoryBean){
        SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
        factoryBean.setTriggers(cronTriggerFactoryBean.getObject());
        return factoryBean;
    }
}
3. 启动器中放开
java 复制代码
package com.gupaoedu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class GpSpringbootQuartzDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(GpSpringbootQuartzDemoApplication.class, args);
    }

}
1.20 SpringBoot 整合 SpringDataJPA
1.20.1 添加依赖
XML 复制代码
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

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

    <!-- springBoot的启动器 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- mysql -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>

    <!-- druid连接池 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.0.9</version>
    </dependency>
</dependencies>
1.20.2 配置文件
java 复制代码
# jdbc的相关配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/gp?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456

# 配置连接池信息
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource

# 配置JPA的相关参数
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
1.20.3 创建 POJO 对象
java 复制代码
package com.gupaoedu.pojo;

import javax.persistence.*;

@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy =  GenerationType.IDENTITY)
    @Column(name = "id")
    private Integer id;

    @Column(name = "name")
    private String name;

    @Column(name = "age")
    private Integer age;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
1.20.4 创建 Repository 接口
java 复制代码
package com.gupaoedu.dao;

import com.gupaoedu.pojo.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User,Integer> {
}
1.20.5 单元测试
java 复制代码
package com.gupaoedu;

import com.gupaoedu.dao.UserRepository;
import com.gupaoedu.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class GpSpringbootJpaDemoApplicationTests {

    @Autowired
    private UserRepository repository;

    @Test
    public void contextLoads() {
        User user = new User();
        user.setName("gupao");
        user.setAge(4);
        repository.save(user);
    }

}
相关推荐
奋进的芋圆44 分钟前
Java 延时任务实现方案详解(适用于 Spring Boot 3)
java·spring boot·redis·rabbitmq
sxlishaobin1 小时前
设计模式之桥接模式
java·设计模式·桥接模式
model20051 小时前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端
荒诞硬汉1 小时前
JavaBean相关补充
java·开发语言
提笔忘字的帝国2 小时前
【教程】macOS 如何完全卸载 Java 开发环境
java·开发语言·macos
2501_941882482 小时前
从灰度发布到流量切分的互联网工程语法控制与多语言实现实践思路随笔分享
java·开发语言
華勳全栈2 小时前
两天开发完成智能体平台
java·spring·go
alonewolf_992 小时前
Spring MVC重点功能底层源码深度解析
java·spring·mvc
沛沛老爹2 小时前
Java泛型擦除:原理、实践与应对策略
java·开发语言·人工智能·企业开发·发展趋势·技术原理
专注_每天进步一点点2 小时前
【java开发】写接口文档的札记
java·开发语言