狂神说Springboot

# Unit01-Springboot初识

一、什么是SpringBoot

SpringBoot就是一个javaweb的开发框架,和SpringMVC类似,对比其他javaweb框架的好处,官方说是简化开发,约定大于配置, you can “just run”,能迅速的开发web应用,几行代码开发一个http接口。

Spring Boot 基于 Spring 开发,Spirng Boot 本身并不提供 Spring 框架的核心特性以及扩展功能,

它并不是用来替代 Spring 的解决方案,而是和 Spring 框架紧密结合用于提升 Spring 开发者体验的工具。

多数 Spring Boot 应用只需要很少的 Spring 配置。同时它集成了大量常用的第三方库配置(例如 Redis、MongoDB、Jpa、RabbitMQ、Quartz 等等),Spring Boot 应用中这些第三方库几乎可以零配置的开箱即用。

简单来说就是SpringBoot其实不是什么新的框架,它默认配置了很多框架的使用方式,就像maven整合了所有的jar包,spring boot整合了所有的框架 。

Spring Boot 出生名门,从一开始就站在一个比较高的起点,又经过这几年的发展,生态足够完善,Spring Boot 已经当之无愧成为 Java 领域最热门的技术。

Spring Boot的主要优点:

  • 为所有Spring开发者更快的入门
  • 开箱即用,提供各种默认配置来简化项目配置
  • 内嵌式容器简化Web项目
  • 没有冗余代码生成和XML配置的要求

# Unit02-Springboot第一个程序

一、可以在官网上创建

二、或者在IDEA上创建【推荐】

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xXsas8FT-1659711523283)(# Unit01-Springboot第一个程序.assets/image-20220505161505632.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fJMA3r3s-1659711523286)(# Unit01-Springboot第一个程序.assets/image-20220505161536730.png)]在这里插入图片描述

编写一个Controller

1、在主程序的同级目录下,新建一个controller包,一定要在同级目录下,否则识别不到

2、在包中新建一个HelloController类

@RestController
@RequestMapping("/hello")
public class HelloController {
    @GetMapping("/hello")
    public String hellotest(){
        return "hello";
    }
}

3、测试,从浏览器发起请求

在这里插入图片描述

1、如何更改端口号

在application.properties中编写

# 更改端口号
server.port=8081

2、如何更改banner

在线生成:Spring Boot banner在线生成工具,制作下载banner.txt,修改替换banner.txt文字实现自定义,个性化启动banner-bootschool.net

1、在resourse中新建banner.txt,放入图片

在这里插入图片描述

注意小标,如果有,则正常

2、运行测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yXG2a8mP-1659711523294)(# Unit02-Springboot第一个程序.assets/image-20220505164241609.png)]

我们没有做过多的事情,便实现了功能,SpringBoot是如此的神奇!

# Unit03-Springboot原理初探

一、pom.xml

其中它主要是依赖一个父项目,主要是管理项目的资源过滤及插件!

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.6.7</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

点进去,发现还有一个父依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.6.7</version>
</parent>

这里才是真正管理SpringBoot应用里面所有依赖版本的地方,SpringBoot的版本控制中心;

以后我们导入依赖默认是不需要写版本;但是如果导入的包没有在依赖中管理着就需要手动配置版本了;

二、启动器

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

springboot-boot-starter-xxx:就是spring-boot的场景启动器

spring-boot-starter-web:帮我们导入了web模块正常运行所依赖的组件;

SpringBoot将所有的功能场景都抽取出来,做成一个个的starter (启动器),只需要在项目中引入这些starter即可,所有相关的依赖都会导入进来 , 我们要用什么功能就导入什么样的场景启动器即可 ;我们未来也可以自己自定义 starter;

三、主程序

//@SpringBootApplication 来标注这个类是一个Spring Boot应用
@SpringBootApplication
public class SpringbootApplication {

   public static void main(String[] args) {
     //以为是启动了一个方法,没想到启动了一个服务
      SpringApplication.run(SpringbootApplication.class, args);
   }
}
@SpringBootApplication

自动配置根源所在!
在这里插入图片描述

自动装配原理分析:

http://assets.processon.com/chart_image/62527e6e7d9c080729b42b77.png

结论:

  1. SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值
  2. 将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;
  3. 整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;
  4. 它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件 ;
  5. 有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;
SpringApplication

这个类主要做了以下四件事情:

1、推断应用的类型是普通的项目还是Web项目

2、查找并加载所有可用初始化器 , 设置到initializers属性中

3、找出所有的应用程序监听器,设置到listeners属性中

4、推断并设置main方法的定义类,找到运行的主类

# Unit04-SpringBootyaml语法

一、配置文件

SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的

  • application.properties

    • 语法结构 :key=value
  • application.yaml

    • 语法结构 :key:空格 value

**配置文件的作用 :**修改SpringBoot自动配置的默认值

二、yaml概述

YAML(/ˈjæməl/,尾音类似camel骆驼)是一个可读性高,用来表达数据序列化的格式。

这种语言以数据作为中心,而不是以标记语言为重点!

三、yaml基础语法

说明:语法要求严格!

1、空格不能省略

2、以缩进来控制层级关系,只要是左边对齐的一列数据都是同一个层级的。

3、属性和值的大小写都是十分敏感的。

# 普通的key-value
name: chenpeixue

#对象
student:
 name: chenpeixue
 age: 21

#行内写法
boy: {name: chenpeixue,age: 21}

#数组
pats:
  - dog
  - cat
  - pig

# 行内写法
animals: [dog,cat,pig]

注意:

  • “ ” 双引号,不会转义字符串里面的特殊字符 , 特殊字符会作为本身想表示的意思;

    比如 :name: “kuang \n shen” 输出 :kuang 换行 shen

  • ‘’ 单引号,会转义特殊字符 , 特殊字符最终会变成和普通字符一样输出

    比如 :name: ‘kuang \n shen’ 输出 :kuang \n shen

四、给属性赋值

1、在springboot项目中的resources目录下新建一个文件 application.yml

2、编写一个实体类 Dog;

@Component
public class Dog {
    @Value("阿黄")
    private String name;
    @Value("1")
    private Integer age;
//有参,无参构造器,set\get toString
}

3、我们在编写一个复杂一点的实体类:Person 类

/*
@ConfigurationProperties作用:
将配置文件中配置的每一个属性的值,映射到这个组件中;
告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定
参数 prefix = “person” : 将配置文件中的person下面的所有属性一一对应
*/
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
    private String name;
    private Integer age;
    private boolean happy;
    private Date birth;
    private Map<String,Object> map;
    private List<Object> list;
    private Dog dog;
//有参,无参构造器,set\get toString
}

在这里插入图片描述

解决爆红:在pom.xml中导入依赖

<!-- 导入配置文件处理器,配置文件进行绑定就会有提示,需要重启 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-configuration-processor</artifactId>
  <optional>true</optional>
</dependency>

4、我们来使用yaml配置的方式进行注入,

person:
  name: chenpeixue
  age: 3
  happy: false
  birth: 2000/01/01
  map: {k1: v1,k2: v2}
  list:
    - code
    - girl
    - music
  dog:
    name: 阿黄
    age: 1

5、测试

@SpringBootTest
class SpringbootApplicationTests {
    @Autowired
    private Dog dog;
    @Autowired
    private Person person;
    @Test
    void contextLoads() {
        System.out.println(dog);
        System.out.println(person);
    }
}

结果:

在这里插入图片描述

配置文件占位符

person:
  name: chenpeixue${random.uuid} # 随机uuid
  age: ${random.int}  # 随机int
  happy: false
  birth: 2000/01/01
  map: {k1: v1,k2: v2}
  list:
    - code
    - girl
    - music
  dog:
    name: ${person.hello:other}_旺财
    age: 1

person.hello:other 对象不存在时,返回other

测试结果:

在这里插入图片描述

在这里插入图片描述

五、松散绑定

application.yaml

dog:
  first-name: 旺财
  age: 1

pojo

@Component
@ConfigurationProperties(prefix = "dog")
public class Dog {
    private String firstname;
    private Integer age;

    public Dog(){

    }

    public Dog(String firstname, Integer age) {
        this.firstname = firstname;
        this.age = age;
    }

    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public Integer getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Dog{" +
                "firstname='" + firstname + '\'' +
                ", age=" + age +
                '}';
    }
}

测试:

@SpringBootTest
class SpringbootApplicationTests {
    @Autowired
    private Dog dog;
    @Test
    void contextLoads() {
        System.out.println(dog);
    }
}

结果:

在这里插入图片描述

# Unit05-SpringBoot多环境配置

一、多环境切换

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oDS32oY3-1659712125251)(# Unit05-SpringBoot多环境配置.assets/image-20220506210424936.png)]

我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml , 用来指定多个环境版本;

例如:

application-test.properties 代表测试环境配置

application-dev.properties 代表开发环境配置

但是Springboot并不会直接启动这些配置文件,它默认使用application.properties主配置

文件

我们需要通过一个配置来选择需要激活的环境:

#比如在配置文件中指定使用dev环境,我们可以通过设置不同的端口号进行测试;
#我们启动SpringBoot,就可以看到已经切换到dev下的配置了;
spring.profiles.active=dev

二、yaml的多文档块


server:
  port: 8081
#选择要激活那个环境块
spring:
  profiles:
    active: prod

---
server:
  port: 8083
spring:
  profiles: dev #配置环境的名称


---

server:
  port: 8084
spring:
  profiles: prod  #配置环境的名称

# Unit06-SpringBoot获取静态资源

一、使用Webjars

在这里插入图片描述

webjars官网:WebJars - Web Libraries in Jars

导入依赖

<dependency>
    <groupId>org.webjars.npm</groupId>
    <artifactId>jquery</artifactId>
    <version>3.6.0</version>
</dependency>

结果:

在这里插入图片描述

IDEA快捷键:打开收缩源码:Ctrl+Shift+/-

二、其它

  • public、 static、/**、resources localtast:8080/

在这里插入图片描述

# Unit07-springboot首页定制

在templates中编写的html,必须通过controller访问

一、Thymeleaf

pdf:Tutorial: Using Thymeleaf

**Thymeleaf 是一款用于渲染 XML/XHTML/HTML5 内容的模板引擎。**它与 JSP,Velocity,FreeMaker 等模板引擎类似,也可以轻易地与 Spring MVC 等 Web 框架集成。与其它模板引擎相比,Thymeleaf 最大的特点是,即使不启动 Web 应用,也可以直接在浏览器中打开并正确显示模板页面 。

1、编写controller

@Controller
public class IndexController {
    @RequestMapping("/index")
    public String index(Model model){
        model.addAttribute("msg","<h1>helloworld</h1>");
        model.addAttribute("tests", Arrays.asList("java","mysql","springboot"));
        return "index";
    }
}

2、在templates下编写index.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h2>首页</h2>
<!--th:text:没有转义-->
<!--th:utext:会转义-->
<div th:text="${msg}"></div>
<div th:utext="${msg}"></div>
<hr>
<div th:each="test:${tests}" th:text="${test}"></div>
</body>
</html>

结果:

在这里插入图片描述

# Unit08-Springbootmvc扩展

一、视图解析器

在config包下,编写MyMvcConfig

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

    //ViewResolver:实现了视图解析器接口的类,我们可以把它看成视图解析器

    //将自定义视图解析器放到Bean中
    @Bean
    public ViewResolver myViewResolver(){
        return new myViewResolver();
    }

    //自定义了一个自己的属兔解析器myViewResolver
    public static class myViewResolver implements ViewResolver{
        @Override
        public View resolveViewName(String viewName, Locale locale) throws Exception {
            return null;
        }
    }
}

# Unit09-springboot员工管理系统

一、首页配置

1、导入静态资源

2、注意点,所有页面的静态资源都需要使用thymeleaf接管;(导入thymeleaf依赖)

3、url: @{}

4、新建config目录,编写MyMvcConfig类

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/index.html").setViewName("index");
    }
}

准备工作:

pojo

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Department {
    private Integer id;
    private String departmentName;
}
@Data
@NoArgsConstructor
public class Employee {
    private Integer id;
    private String lastname;
    private String email;
    private Integer gender;
    private Department department;
    private Date birth;

    public Employee(Integer id, String lastname, String email, Integer gender, Department department) {
        this.id = id;
        this.lastname = lastname;
        this.email = email;
        this.gender = gender;
        this.department = department;
        this.birth = new Date();
    }
}

dao:

@Repository
public class DepartmentDao {
//    模拟数据库中的数据
    private static Map<Integer,Department> departments = null;

    static {
        departments = new HashMap<Integer, Department>();//创建一个部门表

        departments.put(101,new Department(101,"教学部"));
        departments.put(102,new Department(102,"教研部"));
        departments.put(103,new Department(103,"市场部"));
        departments.put(104,new Department(104,"运营部"));
        departments.put(105,new Department(105,"后勤部"));
        departments.put(106,new Department(106,"管理部"));
    }

//    获得部门所有的信息
    public Collection<Department> getDepartments(){
        return departments.values();
    }
//    通过id查询部门的信息
    public Department departmentById(Integer id){
        return departments.get(id);
    }
}
@Repository
public class EmployeeDao {
    //    模拟数据库中的数据
    private static Map<Integer, Employee> employees = null;
    @Autowired
    private DepartmentDao departments;

    static {
        employees = new HashMap<Integer, Employee>();
        employees.put(1001, new Employee(1001, "张一", "485945684@qq.com", 1, new Department(101, "教学部")));
        employees.put(1002, new Employee(1002, "张二", "485945684@qq.com", 0, new Department(102, "教研部")));
        employees.put(1003, new Employee(1003, "张三", "485945684@qq.com", 1, new Department(103, "市场部")));
        employees.put(1004, new Employee(1004, "张四", "485945684@qq.com", 0, new Department(104, "运营部")));
        employees.put(1005, new Employee(1005, "张五", "485945684@qq.com", 1, new Department(105, "后勤部")));
        employees.put(1006, new Employee(1006, "张六", "485945684@qq.com", 0, new Department(106, "管理部")));
    }
//主键
    private static Integer employeeid = 1006;

//    添加一个员工
    public void addemployees(Employee employee){
           if(employee.getId() == null){
            employee.setId(employeeid);
            employeeid++;
        }

        employee.setDepartment(departments.departmentById(employee.getDepartment().getId()));
        employees.put(employee.getId(),employee);
    }
//    查询全部员工
    public Collection<Employee> allemployees(){
        return employees.values();
    }
//通过id查询员工
    public Employee employeeById(Integer id){
        return employees.get(id);
    }
//   通过id删除员工
    public void deleteEmploteeById(Integer id){
        employees.remove(id);
    }
}

二、国际化

保证都是utf-8编码,防止乱码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3yeeMjpj-1659712294507)(Untitled.assets/image-20220509155245792.png)]

1、在resources中新建i18n目录,编写properties

在这里插入图片描述

login.properties

login.doginbtn=登录
login.password=密码
login.remember=记住我
login.tip=请登录
login.username=用户名

login_en_US.properties

login.doginbtn=Sign in
login.password=password
login.remember=Remember me
login.tip=Please sign in
login.username=username

login_zh_CN.properties

login.doginbtn=登录
login.password=密码
login.remember=记住我
login.tip=请登录
login.username=用户名

2、在index.html的路径上添加属性

<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>

index.html

<!DOCTYPE html>
<html lang="en">
<html xmlns:th="http://www.thymeleaf.org">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
		<meta name="description" content="">
		<meta name="author" content="">
		<title>Signin Template for Bootstrap</title>
		<!-- Bootstrap core CSS -->
		<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">
		<!-- Custom styles for this template -->
		<link th:href="@{/css/signin.css}" rel="stylesheet">
	</head>

	<body class="text-center">
		<form class="form-signin" action="dashboard.html">
			<img class="mb-4" th:src="@{/img/bootstrap-solid.svg}" alt="" width="72" height="72">
			<h1 class="h3 mb-3 font-weight-normal" th:text="#{login.tip}">Please sign in</h1>
			<label class="sr-only">Username</label>
			<input type="text" class="form-control" th:placeholder="#{login.username}" required="" autofocus="">
			<label class="sr-only">Password</label>
			<input type="password" class="form-control" th:placeholder="#{login.password}" required="">
			<div class="checkbox mb-3">
				<label>
          <input type="checkbox" value="remember-me"> [[#{login.remember}]]
        </label>
			</div>
			<button class="btn btn-lg btn-primary btn-block" type="submit"> [[#{login.doginbtn}]]</button>
			<p class="mt-5 mb-3 text-muted">© 2017-2018</p>
			<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
			<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
		</form>
	</body>
</html>

国际化:#{}

3、实现按钮自动切换,我们需要自定义一个组件LocaleResolver,编写MyLocaleResolver类

public class MyLocaleResolver implements LocaleResolver {
//   解析请求
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
//        获取请求中的语言参数
        String language = request.getParameter("l");
        System.out.println("DeBug---->"+language);
//        如果没有就使用默认的
        Locale locale = Locale.getDefault();
        if(!StringUtils.isEmpty(language)){
            String[] split = language.split("_");
            locale = new Locale(split[0], split[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {

    }
}

3、在MyMvcConfig中注入bean

    @Bean
    public LocaleResolver localeResolver(){
        return new MyLocaleResolver();
    }

结果:

在这里插入图片描述

三、登录-拦截器

1、index.html 用来显示错误登录提示和权限错误提示

<p style="color: red" th:text="${msg}" th:if="${msg!=null}"></p>

2、在config下新建LoginHandlerInterceptor,编写拦截器

public class LoginHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object loginUser = request.getSession().getAttribute("loginUser");
        if(loginUser == null){
            request.setAttribute("msg","没有权限,请先登录!");
            request.getRequestDispatcher("/index.html").forward(request,response);
            return false;
        }else {
            return true;
        }
    }
}

3、在myconfig中添加拦截器

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new LoginHandlerInterceptor()).addPathPatterns("/**")
        .excludePathPatterns("/","/index.html","/user/login","/css/**","/js/**","/img/**");
}

4、LoginController

@Controller
@RequestMapping("/user")
public class LoginController {
    @RequestMapping("/login")
    public String login(@RequestParam("username") String username, @RequestParam("password") String password,
                        Model model, HttpSession session){
        if(username!=null&&"123456".equals(password)){
            session.setAttribute("loginUser",username);
            return "redirect:/main.html";
        }else{
            model.addAttribute("msg","用户名或密码错误!");
            return "index";
        }
    }
}

四、员工列表展示

1、提取公共页面 commons下的commons.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

<!--导航栏-->
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0" th:fragment="topbar">
    <a class="navbar-brand col-sm-3 col-md-2 mr-0" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">[[${session.loginUser}]]</a>
    <input class="form-control form-control-dark w-100" type="text" placeholder="Search" aria-label="Search">
    <ul class="navbar-nav px-3">
        <li class="nav-item text-nowrap">
            <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">退出</a>
        </li>
    </ul>
</nav>
<!--侧边栏-->
<nav class="col-md-2 d-none d-md-block bg-light sidebar" th:fragment="sidebar">
    <div class="sidebar-sticky">
        <ul class="nav flex-column">
            <li class="nav-item">
                <a th:class="${active=='main.html'?'nav-link active':'nav-link'}" th:href="@{/index.html}">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-home">
                        <path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path>
                        <polyline points="9 22 9 12 15 12 15 22"></polyline>
                    </svg>
                    首页 <span class="sr-only">(current)</span>
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file">
                        <path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"></path>
                        <polyline points="13 2 13 9 20 9"></polyline>
                    </svg>
                    Orders
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-shopping-cart">
                        <circle cx="9" cy="21" r="1"></circle>
                        <circle cx="20" cy="21" r="1"></circle>
                        <path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>
                    </svg>
                    Products
                </a>
            </li>
            <li class="nav-item">
                <a th:class="${active=='list.html'?'nav-link active':'nav-link'}" th:href="@{/allemployee}">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-users">
                        <path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
                        <circle cx="9" cy="7" r="4"></circle>
                        <path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
                        <path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
                    </svg>
                    员工列表
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-bar-chart-2">
                        <line x1="18" y1="20" x2="18" y2="10"></line>
                        <line x1="12" y1="20" x2="12" y2="4"></line>
                        <line x1="6" y1="20" x2="6" y2="14"></line>
                    </svg>
                    Reports
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-layers">
                        <polygon points="12 2 2 7 12 12 22 7 12 2"></polygon>
                        <polyline points="2 17 12 22 22 17"></polyline>
                        <polyline points="2 12 12 17 22 12"></polyline>
                    </svg>
                    Integrations
                </a>
            </li>
        </ul>

        <h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted">
            <span>Saved reports</span>
            <a class="d-flex align-items-center text-muted" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-plus-circle"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="8" x2="12" y2="16"></line><line x1="8" y1="12" x2="16" y2="12"></line></svg>
            </a>
        </h6>
        <ul class="nav flex-column mb-2">
            <li class="nav-item">
                <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text">
                        <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
                        <polyline points="14 2 14 8 20 8"></polyline>
                        <line x1="16" y1="13" x2="8" y2="13"></line>
                        <line x1="16" y1="17" x2="8" y2="17"></line>
                        <polyline points="10 9 9 9 8 9"></polyline>
                    </svg>
                    Current month
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text">
                        <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
                        <polyline points="14 2 14 8 20 8"></polyline>
                        <line x1="16" y1="13" x2="8" y2="13"></line>
                        <line x1="16" y1="17" x2="8" y2="17"></line>
                        <polyline points="10 9 9 9 8 9"></polyline>
                    </svg>
                    Last quarter
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text">
                        <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
                        <polyline points="14 2 14 8 20 8"></polyline>
                        <line x1="16" y1="13" x2="8" y2="13"></line>
                        <line x1="16" y1="17" x2="8" y2="17"></line>
                        <polyline points="10 9 9 9 8 9"></polyline>
                    </svg>
                    Social engagement
                </a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="http://getbootstrap.com/docs/4.0/examples/dashboard/#">
                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-file-text">
                        <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
                        <polyline points="14 2 14 8 20 8"></polyline>
                        <line x1="16" y1="13" x2="8" y2="13"></line>
                        <line x1="16" y1="17" x2="8" y2="17"></line>
                        <polyline points="10 9 9 9 8 9"></polyline>
                    </svg>
                    Year-end sale
                </a>
            </li>
        </ul>
    </div>
</nav>
</html>
  • 在其它位置替换,以实现代码的复用
<div th:replace="~{commons/commons.html::topbar}"></div>

<div th:replace="~{commons/commons.html::sidebar(active='main.html')}"></div>
  • 可以用()来携带参数,实现高亮
*
* Format date with the specified pattern
* Also works with arrays, lists or sets
*/
${#dates.format(date, 'dd/MMM/yyyy HH:mm')}

五、添加员工

1、编写list.html,用来存放员工的信息

<div th:replace="~{commons/commons.html::topbar}"></div>
		<div class="container-fluid">
			<div class="row">
				<div th:replace="~{commons/commons.html::sidebar(active='list.html')}"></div>
				<main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
					<h2>员工列表</h2>
                    <!--向后端发送请求-->
					<div><a class="btn btn-sm btn-success" th:href="@{/toaddemp}">添加员工</a></div>
					<div class="table-responsive">
						<table class="table table-striped table-sm">
							<thead>
								<tr>
									<th>id</th>
									<th>lastname</th>
									<th>email</th>
									<th>gender</th>
									<th>department</th>
									<th>birth</th>
									<th>操作</th>
								</tr>
							</thead>
							<tbody>
								<tr th:each="emp:${emps}">
									<td th:text="${emp.getId()}"></td>
									<td th:text="${emp.getLastname()}"></td>
									<td th:text="${emp.getEmail()}"></td>
									<td th:text="${emp.getGender()==0?'':''}"></td>
									<td th:text="${emp.department.getDepartmentName()}"></td>
									<td th:text="${#dates.format(emp.getBirth(),'dd/MM/yyyy HH:mm:ss')}"></td>
									<td>
										<button class="btn btn-sm btn-primary">修改</button>
										<button class="btn btn-sm btn-danger">s删除</button>
									</td>
								</tr>
							</tbody>
						</table>
					</div>
				</main>
			</div>
		</div>

2、在EmployeeListController中编写controller

@Autowired
DepartmentDao department;

@GetMapping("/toaddemp")
public String addemploy(Model model){
    Collection<Department> departments = department.getDepartments();
    model.addAttribute("dpms",departments);
    return "/emps/addemp";
}

3、在emps下新建addemp.html,使其可以跳转到添加页面

<div th:replace="~{commons/commons.html::topbar}"></div>
<div class="container-fluid">
    <div class="row">
        <div th:replace="~{commons/commons.html::sidebar(active='list.html')}"></div>
        <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
            <form th:action="@{/emp}" method="post">
                <div class="form-group">
                    <label>lastname:</label>
                    <input type="text" name="lastname" class="form-control" placeholder="lastname">
                </div>
                <div class="form-group">
                    <label>Email:</label>
                    <input type="email" name="email" class="form-control" placeholder="Email">
                </div>
                <div class="form-group">
                    <div>
                        <label>gender</label>
                    </div>
                    <div class="form-check form-check-inline">
                        <input class="form-check-input" type="radio" name="gender" value="0">
                        <label class="form-check-label"></label>
                    </div>
                   <div class="form-check form-check-inline">
                        <input class="form-check-input" type="radio" name="gender" value="1">
                        <label class="form-check-label"></label>
                   </div>
                </div>
                <div class="form-group">
                    <label>departmentName:</label>
                    <!--<select class="form-control" name="department.id">
这里不能够传递department对象,只能传递id属性-->
                    <select class="form-control" name="department.id">
                        <option  th:each="dpm:${dpms}" th:text="${dpm.getDepartmentName()}" th:value="${dpm.getId()}"></option>
                    </select>
                </div>
                <div class="form-group">
                    <label>birth:</label>
                    <input type="text" name="birth" class="form-control" placeholder="birth">
                </div>
                <button type="submit" class="btn btn-primary">Submit</button>
            </form>
        </main>
    </div>
</div>

4、接收表单请求,编写controller

@PostMapping("/emp")
public String toaddemploy(Employee employee){
    employeeDao.addemployees(employee);
    return "redirect:/allemployee";
}

六、修改员工

1、修改按钮为链接

<a class="btn btn-sm btn-primary" th:href="@{'/updateemp/'+${emp.getId()}}">修改</a>

2、编写contrtoller

    @GetMapping("/updateemp/{id}")
    public String updateemp(@PathVariable("id")Integer id, Model model){
        Employee employee = employeeDao.employeeById(id);
        model.addAttribute("oldemp",employee);
        Collection<Department> departments = department.getDepartments();
        model.addAttribute("department",departments);
        return "/emps/update";
    }
    @PostMapping("/toupdate")
    public String toupdateemp(Employee employee){
        employeeDao.addemployees(employee);
        return "redirect:/allemployee";
    }

3、编写update.html

<!DOCTYPE html>
<!-- saved from url=(0052)http://getbootstrap.com/docs/4.0/examples/dashboard/ -->
<html lang="en" xmlns:th="http://www.thymeleaf.org">


<body>
<div th:replace="~{commons/commons.html::topbar}"></div>
<div class="container-fluid">
    <div class="row">
        <div th:replace="~{commons/commons.html::sidebar(active='list.html')}"></div>

        <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
            <form th:action="@{/toupdate}"  method="post">
<!--                由于id会自增,在修改时要把id隐藏-->
                <input type="hidden" name="id" th:value="${oldemp.getId()}">
                
                <div class="form-group">
                    <label>lastname:</label>
                    <input th:value="${oldemp.getLastname()}" type="text" name="lastname" class="form-control" placeholder="lastname">
                </div>
                <div class="form-group">
                    <label>Email:</label>
                    <input th:value="${oldemp.getEmail()}" type="email" name="email" class="form-control" placeholder="Email">
                </div>
                <div class="form-group">
                    <div>
                        <label>gender</label>
                    </div>
                    <div class="form-check form-check-inline">
                        <input th:checked="${oldemp.getGender()==0}" class="form-check-input" type="radio" name="gender" value="0">
                        <label class="form-check-label"></label>
                    </div>
                   <div class="form-check form-check-inline">
                        <input th:checked="${oldemp.getGender()==1}" class="form-check-input" type="radio" name="gender" value="1">
                        <label class="form-check-label"></label>
                   </div>
                </div>
                <div class="form-group">
                    <label>departmentName:</label>
                    <select class="form-control" name="department.id">
                        <option th:each="dpm:${department}"  th:selected="${oldemp.getDepartment().getId()==dpm.getId()}" th:text="${dpm.getDepartmentName()}" th:value="${dpm.getId()}"></option>
                    </select>
                </div>
                <div class="form-group">
                    <label>birth:</label>
                    <input th:value="${#dates.format(oldemp.getBirth(),'yyyy-MM-dd hh:mm:ss')}" type="text" name="birth" class="form-control" placeholder="birth">
                </div>
                <button type="submit" class="btn btn-primary">-修改</button>
            </form>
        </main>
    </div>
</div>

<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script type="text/javascript" th:src="@{/js/jquery-3.2.1.slim.min.js}"></script>
<script type="text/javascript" th:src="@{/js/popper.min.js}"></script>
<script type="text/javascript" th:src="@{/js/bootstrap.min.js}" ></script>

<!-- Icons -->
<script type="text/javascript" th:src="@{/js/feather.min.js}" ></script>
<script>
    feather.replace()
</script>



</body>

</html>

七、删除员工

1、修改删除按钮为链接

<a class="btn btn-sm btn-danger" th:href="@{'/deleteemp/'+${emp.getId()}}">删除</a>

2、编写controller

//    删除员工
    @RequestMapping ("/deleteemp/{id}")
    public String todeleteemp(@PathVariable("id")Integer id){
        employeeDao.deleteEmploteeById(id);
        return "redirect:/allemployee";
    }

八、404页面

1、在templates下面新建一个error文件
在这里插入图片描述

九、退出

1、修改commons.html里退出的链接

<a class="nav-link" th:href="@{'/user/logout'}">退出</a>

2、编写controller

    @RequestMapping("/logout")
    public String logout(HttpSession session){
//        将session设置为失效,
        session.invalidate();
        return "redirect:/index.html";
    }

可以使用模板:Layui - 经典开源模块化前端 UI 框架(官网文档镜像站) (layuiweb.com)

x-admin:X-admin - 经典前端网站后台管理模板框架 (xuebingsi.com)

# Unit10-整合JDBC使用

1、新建一个springboot项目

在这里插入图片描述

2、新建application.yml

spring:
  datasource:
    username: root
    password: cpx147258
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=true
    driver-class-name: com.mysql.cj.jdbc.Driver

3、测试

@SpringBootTest
class SpringbootjdbcApplicationTests {

    @Autowired
    DataSource dataSource;

    @Test
    void contextLoads() throws SQLException {
//查看默认的数据源:class com.zaxxer.hikari.HikariDataSource
        System.out.println(dataSource.getClass());
//获取连接
        Connection connection = dataSource.getConnection();

        System.out.println(connection);
//关闭连接
        connection.close();
    }
}

查询用户

新建controller包,新建JCBCController类

  • 使用@RestController注解,必须导入web依赖。
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
@RestController
public class JCBCController {
//    JdbcTemplate是Spring对JDBC的封装,目的是使JDBC更加易于使用。
    @Autowired
    JdbcTemplate jdbcTemplate;
    //查询user中的数据,没有实体类,使用map获取数据
    @GetMapping("/userList")
    public List<Map<String, Object>> userList(){
        String sql = "select * from user";
        List<Map<String, Object>> userList = jdbcTemplate.queryForList(sql);
        return userList;
    }
}
  • 异常(在访问http://localhost:8080/userList时)

在这里插入图片描述

解决方案:
在这里插入图片描述

将XXXApplication.java需放在com.taiyuan 下。

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-smxD7Bgz-1659712445674)(# Unit10-整合JDBC使用.assets/image-20220530115503315.png)]

添加用户

//    添加用户
    @RequestMapping("/addUser")
    public String addUser(){
        String sql = "insert into mybatis.user(id,name,password) values (6,'大大','123123')";
        jdbcTemplate.update(sql);
        return "OK";
    }

修改用户

    //    修改用户
    @RequestMapping("/updateUser{id}")
    public String updateUser(@PathVariable("id") int id){
        String sql = "Update mybatis.user set name =?,password =? where id = "+id;
//        封装
        Object object[] = new Object[2];
        object[0] = "卡卡";
        object[1] = "111111";
        jdbcTemplate.update(sql,object);
        return "updateOK";
    }

删除用户

    //    删除用户
    @RequestMapping("/deleteUser{id}")
    public String deleteUser(@PathVariable("id")int id){
        String sql = "delete from mybatis.user where id = ?";
        jdbcTemplate.update(sql,id);
        return "deleteOK";
    }

# Unit11-整合Druid数据源

一、简介

Druid为监控而生的数据库连接池,它是阿里巴巴开源平台上的一个项目。Druid是Java语言中最好的数据库连接池,Druid能够提供强大的监控和扩展功能.它可以替换DBCP和C3P0连接池。Druid提供了一个高效、功能强大、可扩展性好的数据库连接池。

引入数据源

<!--       Druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.9</version>
        </dependency>

配置数据源

spring:
  datasource:
	type: com.alibaba.druid.pool.DruidDataSource

配置说明
在这里插入图片描述
在这里插入图片描述

二、 后台监控

在config包下新建DruidConfig

@Configuration
public class DruidConfig {
//    想要使用Druid的私有属性,必须进行绑定
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druidDatasourse(){
        return new DruidDataSource();
    }
    @Bean
//    后台监控
    public ServletRegistrationBean statViewServlet(){
        ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
//     后台需要有人登录,账号密码配置
        HashMap<String,String> initParameters = new HashMap<>();
//增加配置
//    登录的key是固定的
        initParameters.put("loginUsername","admin");
        initParameters.put("loginPassword","123456");
//允许谁可以访问
        initParameters.put("allow","");
        //        可以设置初始化参数
        bean.setInitParameters(initParameters);
        return bean;
    }
}

application.yml

spring:
  datasource:
    username: root
    password: cpx147258
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=true
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    #Spring Boot 默认是不注入这些属性值的,需要自己绑定
    #druid 数据源专有配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
    #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
    #则导入 log4j 依赖即可,Maven 地址: https://mvnrepository.com/artifact/log4j/log4j
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b7DaKnh8-1659712543538)(# Unit11-整合Druid数据源.assets/image-20220531104453704.png)]

在这里插入图片描述

# Unit12-整合mybatis

1、新建一个springboot项目

在pom.xml中配置依赖

<!-- mybatis-spring-boot-starter -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.2</version>
</dependency>

2、编写application.properties

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=cpx147258
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&useSSL=true

mybatis.type-aliases-package=com.taiyuan.pojo
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml

导入lombok依赖

<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

3、编写pojo类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private int id;
    private String name;
    private String password;
}

4、编写mapper

//  @Mapper表示这是一个mybatis的mapper类。Dao
//  @Repository用在持久层的接口上,这个注解是将接口的一个实现类交给spring管理。
@Mapper
@Repository
public interface UserMapper {

    List<User> queryUserList();

    User queryUserById(int id);

    int addUser(User user);

    int updateUser(User user);

    int deleteUser(int id);
}

在resources下新建userMapper.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.taiyuan.mapper.UserMapper">
    <select id="queryUserList" resultType="User">
        select * from mybatis.user
    </select>

    <select id="queryUserById" resultType="User">
        select * from mybatis.user where id = #{id}
    </select>

    <insert id="addUser" parameterType="User">
        insert into mybatis.user(id,name,password)values (#{id},#{name},#{password})
    </insert>

    <update id="updateUser" parameterType="User">
        update mybatis.user set name=#{name},password =#{password} where id = #{id}
    </update>

    <delete id="deleteUser" parameterType="int">
        delete from mybatis.user where id = #{id}
    </delete>
</mapper>

5、编写controller

@RestController
public class UserController {
    @Autowired
    private UserMapper userMapper;

    @RequestMapping("/userList")
    public List<User> queryUserList(){
        List<User> users = userMapper.queryUserList();
//        for循环 iter + tab
        for (User user : users) {
            System.out.println(user);
        }
        return users;
    }
    @RequestMapping("/queryuser{id}")
    public User queryUserByid(@PathVariable("id") int id){
        User user = userMapper.queryUserById(id);
//        for循环 iter + tab
        System.out.println(user);
        return user;
    }

    @RequestMapping("/addUser")
    public String addUser(){
        userMapper.addUser(new User(7, "辣辣", "202020"));
        return "ok";
    }
    @RequestMapping("/updateUser")
    public String updateUser(){
        userMapper.updateUser(new User(7, "辣辣", "111111"));
        return "ok";
    }
    @RequestMapping("/deleteUser{id}")
    public String deleteUser(@PathVariable("id") int id){
        userMapper.deleteUser(id);
        return "ok";
    }
}

# Unit13-springsecurity

先搭建环境

一、简介

Spring Security,这是一种基于 Spring AOP 和 Servlet 过滤器的安全框架。它提供全面的安全性解决方案,同时在 Web 请求级和方法调用级处理身份确认和授权。

在这里插入图片描述

详细笔记:

狂神说SpringBoot18:集成SpringSecurity (qq.com)

# Unit14-shiro

一、简介

Apache Shiro 是 Java 的一个安全框架。目前,使用 Apache Shiro 的人越来越多,因为它相当简单,对比 Spring Security,可能没有 Spring Security 做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的 Shiro 就足够了。对于它俩到底哪个好,这个不必纠结,能更简单的解决项目问题就好了。

基本功能点如下图

在这里插入图片描述

  • Authentication:身份认证 / 登录,验证用户是不是拥有相应的身份;
  • Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;
  • Session Management:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通 JavaSE 环境的,也可以是如 Web 环境的;
  • Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
  • Web Support:Web 支持,可以非常容易的集成到 Web 环境;
  • Caching:缓存,比如用户登录后,其用户信息、拥有的角色 / 权限不必每次去查,这样可以提高效率;
  • Concurrency:shiro 支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
  • Testing:提供测试支持;
  • Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
  • Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

首先,我们从外部来看 Shiro 吧,即从应用程序角度的来观察如何使用 Shiro 完成工作

在这里插入图片描述

Subject:主体,代表了当前 “用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是 Subject,如网络爬虫,机器人等;即一个抽象概念;所有 Subject 都绑定到 SecurityManager,与 Subject 的所有交互都会委托给 SecurityManager;可以把 Subject 认为是一个门面;SecurityManager 才是实际的执行者;

SecurityManager:安全管理器;即所有与安全有关的操作都会与 SecurityManager 交互;且它管理着所有 Subject;可以看出它是 Shiro 的核心,它负责与后边介绍的其他组件进行交互,如果学习过 SpringMVC,你可以把它看成 DispatcherServlet 前端控制器;

Realm:域,Shiro 从 Realm 获取安全数据(如用户、角色、权限),就是说 SecurityManager 要验证用户身份,那么它需要从 Realm 获取相应的用户进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色 / 权限进行验证用户是否能进行操作;可以把 Realm 看成 DataSource,即安全数据源。

二、整合shiro

1、新建一个springboot项目

2、导入shiro依赖

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.9.0</version>
</dependency>

3、编写config配置类

  • UserRealm
//自定义的UserRealm
public class UserRealm extends AuthorizingRealm {
//    授权信息
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("授权信息");
        return null;
    }
//身份验证信息
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("身份验证信息");
        return null;
    }
}
  • ShiroConfig
@Configuration
public class ShiroConfig {
//    shiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
//        设置安全管理器
        factoryBean.setSecurityManager(defaultWebSecurityManager);
        return factoryBean;
    }

//    DafaultwebSecurityManager
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){

        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //与UserRealm相关联-通过传参
        securityManager.setRealm(userRealm);

        return securityManager;
    }

//  1.  创建 realm对象  自定义创建,并交给spring托管
    @Bean
    public UserRealm userRealm(){
        return new UserRealm();
    }
}

4、新建几个页面

在这里插入图片描述

addUser.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>add==============User</h1>
</body>
</html>

updateUser.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>upda===========teUser</h1>
</body>
</html>

index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>首页</h1>
<hr>
<a th:href="@{/user/add}">addUser</a>
<hr>
<a th:href="@{/user/update}">updateUser</a>
</body>
</html>

5、编写controller

@Controller
public class MyController {

    @RequestMapping({"/","/index"})
    public String index(){
        return "index";
    }

    @RequestMapping("/user/add")
    public String addUser(){
        return "user/addUser";
    }

    @RequestMapping("/user/update")
    public String updateUser(){
        return "user/updateUser";
    }
}

1、登录拦截

ShiroConfig

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean Bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        Bean.setSecurityManager(defaultWebSecurityManager);
        //添加shiro的内置过滤器
        /*
        * anon: 无需认证就可以访问
        * authc: 必须认证了才能访问
        * user: 必须拥有  记住我  功能才能用
        * perms: 拥有对某个资源的权限才能访问
        * role:  拥有某个角色权限才能访问
        * */
        Map<String, String> filterMap = new LinkedHashMap<>();
//        filterMap.put("/user/add","authc");
//        filterMap.put("/user/update","authc");

        //支持通配符
        filterMap.put("/user/*","authc");
        Bean.setFilterChainDefinitionMap(filterMap);

        //设置登录的请求
        Bean.setLoginUrl("/toLogin");

        return Bean;
    }

新建login页面

<!DOCTYPE html>
<html lang="en"  xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>登录</h1>
<hr>
<!--当 msg 爆红,可以添加以下注解-->
<!--@thymesVar id="msg" type="String"-->
<p th:text="${msg}" style="color: #ff0000"></p>
<form th:action="@{/login}" method="post">
    <p>用户名:<input type="text" name="username"></p>
    <p>密码:<input type="password" name="password"></p>
    <p><input type="submit"></p>
</form>
</body>
</html>

编写controller

@RequestMapping("/toLogin")
public String toLogin(){
    return "login";
}

2、登录认证

编写controller

@RequestMapping("/login")
public String login(String username,String password, Model model){
    //获取当前的用户
    Subject subject = SecurityUtils.getSubject();
    //封装用户的信息
    UsernamePasswordToken token = new UsernamePasswordToken(username, password);
    try {
        //执行登录的方法,如果没有异常,则ok
        subject.login(token);
        return "index";
    }catch (UnknownAccountException e){
        model.addAttribute("msg","用户名错误");
        return "login";
    }catch (IncorrectCredentialsException e){
        model.addAttribute("msg","密码错误");
        return "login";
    }
}

UserRealm

//身份验证信息
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken Token) throws AuthenticationException {
        System.out.println("======身份验证信息=======");
        //应该从数据库中去数据
        String usernaem ="admin";
        String password = "123456";

        UsernamePasswordToken userToken = (UsernamePasswordToken) Token;

        if(!userToken.getUsername().equals(usernaem)){
            //抛出异常  UnknownAccountException
            return null;
        }
        //密码认证:shiro去做
        return new SimpleAuthenticationInfo("",password,"");
    }

3、shiro 整合mybatis

1、导入依赖

<!-- log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
<!-- mysql -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!--       Druid-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>
<!-- mybatis-spring-boot-starter -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.2</version>
</dependency>

2、编写application.yml

spring:
  datasource:
    username: root
    password: cpx147258
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=true
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    #Spring Boot 默认是不注入这些属性值的,需要自己绑定
    #druid 数据源专有配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
    #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
    #则导入 log4j 依赖即可,Maven 地址: https://mvnrepository.com/artifact/log4j/log4j
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

3、连接数据库 mybatis

4、application.properties

mybatis.type-aliases-package=com.taiyuan.pojo
mybatis.mapper-locations=classpath:mapper/*.xml

5、导入lombok,编写pojo

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String password;
}

6、新建mapper UserMapper

@Repository
@Mapper
public interface UserMapper {

    public User queryUserbyname(String name);
}

userMapper.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.taiyuan.mapper.UserMapper">
    <select id="queryUserbyname" parameterType="String" resultType="User">
        select * from mybatis.user where name = #{name}
    </select>
</mapper>

7、新建service UserService

public interface UserService {
    public User queryUserbyname(String name);
}

UserServiceImpl

@Service
public class UserServiceImpl implements UserService{
    @Autowired
    UserMapper userMapper;

    @Override
    public User queryUserbyname(String name) {
        return userMapper.queryUserbyname(name);
    }
}

8、修改UserRealm

//自定义的UserRealm
public class UserRealm extends AuthorizingRealm {
    @Autowired
    UserService userService;
//    授权信息
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("======授权信息=====");
        return null;
    }
//身份验证信息
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken Token) throws AuthenticationException {
        System.out.println("======身份验证信息=======");
        UsernamePasswordToken userToken = (UsernamePasswordToken) Token;
        //应该从数据库中去数据
        User user = userService.queryUserbyname(userToken.getUsername());
        if(user==null){
            return null;    //UnknownAccountException
        }
        //密码认证:shiro去做
        return new SimpleAuthenticationInfo("",user.getPassword(),"");
    }
}

4、shiro请求授权

ShiroConfig

//授权——未授权,应跳转到未授权页面
filterMap.put("/user/add","perms[user:add]");

在这里插入图片描述

编写controller

@RequestMapping("/unauthorized")
@ResponseBody
public String unauthorized(){
    return "未授权,不可访问";
}

设置未授权的请求

//设置未授权的请求
Bean.setUnauthorizedUrl("/unauthorized");

在这里插入图片描述

对用户进行授权

@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    System.out.println("======授权信息=====");
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

    info.addStringPermission("user:add");

    return info;
}

在这里插入图片描述

但这样对所有的用户都授权不符合需求,应该数据库中有类似于授权表

修改数据库

在这里插入图片描述
在这里插入图片描述

修改pojo

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String password;
    private String parms;
}

UserRealm

return new SimpleAuthenticationInfo(user,user.getPassword(),"");
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    System.out.println("======授权信息=====");
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    //拿到当前登录的用户——可以通过principal
    Subject subject = SecurityUtils.getSubject();
    User user = (User)subject.getPrincipal();
    //设置用户的权限
    info.addStringPermission(user.getParms());
    return info;
}

5、shiro整合thymeleaf

1、导入依赖

<!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>2.1.0</version>
</dependency>

2、在ShiroConfig中配置

//ShiroDialect  用来整合shiro、thymeleaf
@Bean
public ShiroDialect getShiroDialect(){
    return new ShiroDialect();
}

用session来判断是否显示

Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession();
session.setAttribute("loginuser",user);

3、index.html

<!DOCTYPE html>
<html lang="en"  xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>首页</h1>

<div data-shiro-hasPermission="user:add">
    <a th:href="@{/user/add}">addUser</a>
</div>

<div data-shiro-hasPermission="user:update">
    <a th:href="@{/user/update}">updateUser</a>
</div>
<div th:if="${session.loginuser==null}">
    <a th:href="@{/toLogin}">登录</a>
</div>

</body>
</html>

完整的UserRealm

package com.taiyuan.config;

import com.taiyuan.pojo.User;
import com.taiyuan.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * @author chenpeixue
 * @version 1.0
 */
//自定义的UserRealm
public class UserRealm extends AuthorizingRealm {
    @Autowired
    UserService userService;
//    授权信息
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("======授权信息=====");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //拿到当前登录的用户——可以通过principal
        Subject subject = SecurityUtils.getSubject();
        User user = (User)subject.getPrincipal();
        //设置用户的权限
        info.addStringPermission(user.getParms());
        return info;
    }
//身份验证信息
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken Token) throws AuthenticationException {
        System.out.println("======身份验证信息=======");
        UsernamePasswordToken userToken = (UsernamePasswordToken) Token;
        //应该从数据库中去数据
        User user = userService.queryUserbyname(userToken.getUsername());
        if(user==null){
            return null;    //UnknownAccountException
        }
        Subject subject = SecurityUtils.getSubject();
        Session session = subject.getSession();
        session.setAttribute("loginuser",user);
        //密码认证:shiro去做
        return new SimpleAuthenticationInfo(user,user.getPassword(),"");
    }
}

完整的ShiroConfig·

package com.taiyuan.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author chenpeixue
 * @version 1.0
 */
@Configuration
public class ShiroConfig {
    //3. shiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean Bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        Bean.setSecurityManager(defaultWebSecurityManager);
        //添加shiro的内置过滤器
        /*
        * anon: 无需认证就可以访问
        * authc: 必须认证了才能访问
        * user: 必须拥有  记住我  功能才能用
        * perms: 拥有对某个资源的权限才能访问
        * role:  拥有某个角色权限才能访问
        * */
        Map<String, String> filterMap = new LinkedHashMap<>();
//        filterMap.put("/user/add","authc");
//        filterMap.put("/user/update","authc");

        //授权——未授权,应跳转到未授权页面
        filterMap.put("/user/add","perms[user:add]");
        filterMap.put("/user/update","perms[user:update]");
        //支持通配符
        filterMap.put("/user/*","authc");
        Bean.setFilterChainDefinitionMap(filterMap);

        //设置登录的请求
        Bean.setLoginUrl("/toLogin");
        //设置未授权的请求
        Bean.setUnauthorizedUrl("/unauthorized");
        return Bean;
    }

    //2. DafaultwebSecurityManager
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){

        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //与UserRealm相关联-通过传参
        securityManager.setRealm(userRealm);

        return securityManager;
    }

    //1.创建 realm对象  自定义创建,并交给spring托管
    @Bean
    public UserRealm userRealm(){
        return new UserRealm();
    }

    //ShiroDialect  用来整合shiro、thymeleaf
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }
}

# Unit15-springboot-swagger

一、简介

Swagger是一款RESTFUL接口的文档在线自动生成+功能测试功能软件。Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务。目标是使客户端和文件系统作为服务器以同样的速度来更新文件的方法,参数和模型紧密集成到服务器。

这个解释简单点来讲就是说,swagger是一款可以根据resutful风格生成的生成的接口开发文档,并且支持做测试的一款中间软件。

官网:API Documentation & Design Tools for Teams | Swagger

二、集成swagger

1、新建一个springboot web项目

2、导入依赖

一:引入Swagger依赖库
<!--引入swagger-->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.7.0</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.7.0</version>
</dependency>

<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>

<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

3、编写一个hello工程

4、配置swagger==》config

@Configuration
@EnableSwagger2
public class SwaggerConfig {
}

5、测试 Swagger UI
在这里插入图片描述

三、swagger配置

package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.GetMapping;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;

@Configuration
@EnableSwagger2
public class SwaggerConfig {
//    配置swagger的Docket的bean实例
    @Bean
    public Docket docket(){
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
//                RequestHandlerSelectors: 配置扫描接口的方式
//                basePackage: 指定扫描包的方式
//                any() 扫描全部包
//                none() 全部不扫描
//                withClassAnnotation
                .apis(RequestHandlerSelectors.withClassAnnotation(GetMapping.class))
//                paths  : 要过滤的路径
                .paths(PathSelectors.ant("/example/**"))
                .build();
    }
//    配置swagger信息apiInfo
    public ApiInfo apiInfo(){
//        作者信息
        Contact DEFAULT_CONTACT = new Contact("陈培学", "https://blog.csdn.net/m0_53550060?spm=1000.2115.3001.5343", "485945684@qq.com");
        return new ApiInfo(
                "swagger文档",
                "keep trying",
                "1.0",
                "https://blog.csdn.net/m0_53550060?spm=1000.2115.3001.5343",
                DEFAULT_CONTACT,
                "Apache 2.0",
                "http://www.apache.org/licenses/LICENSE-2.0",
                new ArrayList()
        );
    }
}

swagger在生产环境中使用,在发布的时候不去使用!

在这里插入图片描述

@Profile({"pro","text"})
//注解@Profile({“dev”,“test”}) 表示在开发或测试环境开启,而在生产关闭。(推荐使用)

swagger分组

 .groupName("快乐小子")

如何去分多个组?——用多个doctor

package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.ArrayList;

@Configuration
@EnableSwagger2
@Profile({"pro","text"})
//注解@Profile({“dev”,“test”}) 表示在开发或测试环境开启,而在生产关闭。(推荐使用)
public class SwaggerConfig {

    @Bean
    public Docket docket1(){
        return new Docket(DocumentationType.SWAGGER_2).groupName("快乐小子1");
    }
    @Bean
    public Docket docket2(){
        return new Docket(DocumentationType.SWAGGER_2).groupName("快乐小子2");
    }
    @Bean
    public Docket docket3(){
        return new Docket(DocumentationType.SWAGGER_2).groupName("快乐小子3");
    }
//    配置swagger的Docket的bean实例
    @Bean
    public Docket docket(Environment environment){
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .groupName("快乐小子")
                .select()
                .apis(RequestHandlerSelectors.withClassAnnotation(GetMapping.class))
                .build();
    }
//    配置swagger信息apiInfo
    public ApiInfo apiInfo(){
//        作者信息
        Contact DEFAULT_CONTACT = new Contact("陈培学", "https://blog.csdn.net/m0_53550060?spm=1000.2115.3001.5343", "485945684@qq.com");
        return new ApiInfo(
                "swagger文档",
                "keep trying",
                "1.0",
                "https://blog.csdn.net/m0_53550060?spm=1000.2115.3001.5343",
                DEFAULT_CONTACT,
                "Apache 2.0",
                "http://www.apache.org/licenses/LICENSE-2.0",
                new ArrayList()
        );
    }
}

在这里插入图片描述

实体类配置

新建一个user的实体类

//@ApiModel 对该接口相关实体类添加额外的描述信息
@ApiModel("用户实体类")
public class User {
//     @ApiModelProperty :注解是作用在 接口相关实体类的参数上 的注解,用来对具体的接口相关实体类中的参数添加额外的描述信息
    @ApiModelProperty("用户名")
    public String username;
    @ApiModelProperty("密码")
    public String password;
}

在这里插入图片描述

接口的配置

//  @ApiOperation  对某个方法/接口进行描述
    @ApiOperation("返回用户名")
    @GetMapping( value = "/hello2")
//  @ApiParam  注解api的参数
    public String hello2(@ApiParam("用户名")String username){
        return "hello" +username;
    }

在这里插入图片描述

# Unit16-springboot任务

一、异步任务

创建一个场景——白屏3秒后显示

@Service
public class AsyncService {
//  @Async注解可以使被修饰的方法成为异步方法
    @Async
    public String hello(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("数据正在处理!!!");
        return "ok";
    }
}
@RestController
public class AsyncController {
    @Autowired
    private AsyncService asyncService;
    @GetMapping(value = "/asynchello")
    public String hello(){
        asyncService.hello();
        return "ok";
    }
}

使用@Async注解使被修饰的方法成为异步方法,并在main中使用@EnableAsync开启异步任务

//@EnableAsync  开启异步任务
@EnableAsync
@SpringBootApplication
public class SpringbootSwaggerApplication {

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

}

二、邮件发送

导入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-mail</artifactId>
    <version>2.1.3.RELEASE</version>
</dependency>

在这里插入图片描述

开启POP3/SMTP服务——>获得密码

application.properties

spring.mail.username=485945684@qq.com
spring.mail.password=bllfojwyjfvqbjcc
spring.mail.host=smtp.qq.com
# 开启加密验证
spring.mail.properties.mail.smtp.ssl.enable=true

发送一个简单的邮件

@SpringBootTest
class SpringbootTeskApplicationTests {

    @Autowired
    JavaMailSenderImpl mailSender;
    @Test
    void contextLoads() {
        SimpleMailMessage message = new SimpleMailMessage();
//        指定邮件标题
        message.setSubject("happy");
//        指定邮件内容
        message.setText("like father,like son");
        message.setFrom("485945684@qq.com");
        message.setTo("485945684@qq.com");
        
        mailSender.send(message);
    }
}

发送一个复杂的邮件

@Test
void contextLoads2() throws MessagingException {
    MimeMessage message = mailSender.createMimeMessage();
    MimeMessageHelper mimeMessage = new MimeMessageHelper(message, true);
    //        正文
    mimeMessage.setSubject("happy");
    mimeMessage.setText("<p style='color:red'>like father,like son</p>",true);
    //      附件
    mimeMessage.addAttachment("1.jpg",new File("C:\\Users\\lenovo\\Desktop\\1.jpg"));
    mimeMessage.addAttachment("2.jpg",new File("C:\\Users\\lenovo\\Desktop\\1.jpg"));

    mimeMessage.setFrom("485945684@qq.com");
    mimeMessage.setTo("485945684@qq.com");
    mailSender.send(message);
}

三、定时任务

1、添加@EnableScheduling注解

//@EnableScheduling 开去定时任务
@EnableScheduling
@SpringBootApplication
public class SpringbootTeskApplication {

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

}

2、编写执行的方法

@Service
public class ScheduledService {
//让方法在某个时间执行
//    cron 秒 分 时 日 月 星期
    @Scheduled(cron = "10 9 17 * * ?")
    public void hello(){
        System.out.println("hello方法被执行了-------");
    }
}

# Unit17-Dubbo、zookeeper

一、什么是Dubbo?

Dubbo是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

RPC是什么

RPC(Remote Procedure Call)远程过程调用协议,一种通过网络从远程计算机上请求服务,而不需要了解底层网络技术的协议。RPC它假定某些协议的存在,例如TPC/UDP等,为通信程序之间携带信息数据。在OSI网络七层模型中,RPC跨越了传输层和应用层,RPC使得开发,包括网络分布式多程序在内的应用程序更加容易。

官网:Apache Dubbo

在这里插入图片描述

节点角色说明

在这里插入图片描述

  1. 服务容器负责启动,加载,运行服务提供者。

  2. 服务提供者在启动时,向注册中心注册自己提供的服务。

  3. 服务消费者在启动时,向注册中心订阅自己所需的服务。

  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。

  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。

  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

二、zookeeper安装

官网:Apache ZooKeeper

在这里插入图片描述

解压,在conf 中新建zoo.cfg

会出现问题——>ZooKeeper audit is disabled

在这里插入图片描述

修改zkServer.cmd 添加**“-Dzookeeper.audit.enable=true”**

在这里插入图片描述

并且要配置好zoo.cfg 中dataDir的路径,确保路径存在

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值