一篇文章教你学会并使用SprintBoot-转自狂神

SprintBoot从零到懂,只要每天学一点,我相信你得生活一定会变更好

微服务阶段

javase:oop

mysql:持久化

html+css+js+jquery框架:视图,框架不熟练,css不好;

javaweb:独立开发mvc三层架构的网站了,原始

ssm:框架:简化了我们的开发流程,配置也开始较为复杂;

以上打成war:通过tomcat运行

spring再简化:SpringBoot -打成jar;其中内嵌tomcat;微服务架构

服务越来越多:springcloud 用来管理纷杂的配置

第一个SpringBoot程序

  • jdk 1.8
  • maven 3.6.1
  • springboot:最新版
  • idea

官方:提供一个快速生成的网站,IDE集成了这个网站!

  • 可以直接在官网下载后,导入idea开发(官网在哪)
  • 直接使用idea创建一个springboot项目
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <!--有一个父项目-->
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.4.0</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.mi</groupId>
   <artifactId>helloworld</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>helloworld</name>
   <description>Demo project for Spring Boot</description>

   <properties>
      <java.version>1.8</java.version>
   </properties>

   <dependencies>
      <!--web依赖:tomcat,dispatcherServlet,xml-->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <!--spring-boot-starter所有的springboot依赖都是使用这个开头的-->

      <!--单元测试-->
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>

   <build>
      <plugins>
         <!--打jar包插件-->
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>

</project>

自动配置原理初探

自动配置:

pom.xml

  • spring-boot-dependencies:核心依赖在父工程中!
  • 我们在写或者引入一些SpringBoot依赖的时候,不需要指定版本,就因为有这些版本仓库

启动器

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
  • 启动器:说白就是SpringBoot的启动场景

  • 比如spring-boot-web,他就会帮我们自动导入web环境所有的依赖

  • SpringBoot会将所有的功能场景,变成一个个启动器

  • 我们要使用什么功能,就只需要找到对应的启动器就可以了 starter

主程序

//@SpringBootApplication:标注这个类是一个SpringBoot的应用
@SpringBootApplication
public class Springboot01HelloworldApplication {

    public static void main(String[] args) {
        //将SpringBoot应用启动
        SpringApplication.run(Springboot01HelloworldApplication.class, args);
    }

}

注解

@SpringBootConfiguration:SpringBoot的配置
    @Configuration:spring配置类
    @Component:说明这也是一个Component组件
@EnableAutoConfiguration:自动配置
    @AutoConfigurationPackage:自动配置包
    	@Import({Registrar.class}):导入选择器'包注册'
    @Import({AutoConfigurationImportSelector.class}): 自动配置导入选择
    
//获取所有的配置
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
		

获取候选的配置

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
    Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
    return configurations;
}

结论:SpringBoot所有自动配置都是在启动的时候扫描并加载:Spring.factories所有的自动配置类都在这里面,但是不一定生效,要判断条件是否成立,只要导入了对应的start,就有了对应的启动器了,有了启动器,我们自动装配就会生效,然后就配置成功了

springboot在启动的时候,在类路径下/META-INF/spring.factories获取指定的值

  1. 将这些自动配置的类导入容器,自动配置就会生效,帮我进行自动配置
  2. 以前我们需要自动配置的东西,现在SpringBoot帮我们做了
  3. 整合javaEE,解决方案和自动配置的东西都在spring-boot-autoconfigure-2.4.0.jar这个包下
  4. 它会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器
  5. 容器中也会存在非常多的xxxAutoConfiguration的文件(@Bean),就是这类给容器中导入了这个场景需要的所有组件;并自动配置,@Configuration, JavaConfig!
  6. 有了自动配置类,免去了我们手动编写配置文件的工作!

SpringApplication原理初探

关于SpringBoot,谈谈你的理解

  • 自动装配
  • run()方法

全面接管SpringMVC的配置! 实操

yaml基础语法

# k = v
# 对空格要求十分高
# 普通的key-value
name: xiaomi

# 对象
student:
  name: xiaomi
  age: 3

# 行内写法

student: {name: xiaomi,age: 3}

# 数组
  pets:
    - cat
    - dog
    - pig

pets: [cat,dog,pig]

yaml可以直接给实体类赋值

public class Person {

//Person{name='xiaomi',
// age=18, happy=false,
// birth=Mon Nov 23 00:00:00 CST 2020,
// maps={k1=v1, k2=v2},
// lists=[code, music, girl],
// dog=Dog{name='旺财', age=3}}

    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;
}
person:
  name: xiaomi${random.uuid}
  age: ${random.int}
  happy: false
  birth: 2020/11/23
  maps: {k1: v1,k2: v2}
  hello: happy
  lists:
    - code
    - music
    - girl
  dog:
    name: ${person.hello:hello}_旺财
    age: 3

  • cp只需要写一次即可,value则需要每个字段都添加
  • 松散绑定:这个什么意思呢?比如我的yaml中写的是last-name,这个和lastName是一样的,-后面跟着的字母默认是大写的。这就是松散绑定
  • JSR303数据校验,这个就是我们可以在字段是增加一层过滤器验证,可以保证数据的合法性
  • 复杂类型封装,yaml中可以封装对象,使用@value就不支持
  • 结论:
  • 配置yml和配置properties都可以获取到值,强烈推荐yml
  • 如果我们某个业务中,只需要获取配置文件中的某个值,可以使用一下@value
  • 如果说,我们专门编写了一个JavaBean来和配置文件进行映射,就直接使用@configurationProperties,不要犹豫!
     

JSR303校验规则

application.yaml优先级

yaml多环境配置

server:
  port: 8081
spring:
  profiles:
    active: dev
---
server:
  port: 8082
spring:
  profiles: dev
---
server:
  port: 8083

spring:
  profiles: test

自动装配原理再探

  1. SpringBoot启动会记载大量的自动配置类
     
  2. 我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中;
  3. 我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在在其中,我们就不要再手动配置了)
  4. 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可;
    1. xxxAutoConfiguration:自动配置类;给容器中添加组件
    2. xxxProperties:封装配置文件中相关属性

SpringBoot Web开发

jar:webapp!

自动装配

SpringBoot到底帮我们配置了什么,我们能不能进行修改?能修改哪些东西?能不能扩展?

  • xxxxAutoConfiguration…向容器中自动配置组件
  • xxxxProperties:自动配置类,装配配置文件中自定义的一些内容!

要解决的问题:

  • 导入静态资源,…
  • 首页
  • jsp,模板引擎Thymeleaf
  • 装配扩展SpringMVC
  • 增删改查
  • 拦截器
  • 国际化!

1、静态资源

总结:

1.在springboot,我们可以使用一下方式处理静态资源

  • webjars
  • public ,static, /**,resources

2.优先级:resource>static(默认)>public

2、模板引擎

结论:只要需要使用thymeleaf,只需要导入对应的依赖就可以了!我们将html放在我们的templates目录下即可!

<!--Thymeleaf-->
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
public static final String DEFAULT_PREFIX = "classpath:/templates/";
public static final String DEFAULT_SUFFIX = ".html";

使用thymeleaf

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

<!--所有的html元素都可以被thymeleaf替换接管 th:元素名-->
<div th:text="${msg}"></div>
</body>
</html>

3、MVC配置原理

//如果你想diy一些定制化的功能,只要写这个组件,然后将它交给springboot,springboot就会帮我们自动装配
//全面扩展SpringMVC
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

    // public interface ViewResolver 实现了视图解析器接口的类,我们就可以把它看做视图解析器

    @Bean
    public ViewResolver MyViewResolver(){
        return new MyViewResolver();
    }
    //自定义了一个自己的视图解析器
    public static class MyViewResolver implements ViewResolver{

        @Override
        public View resolveViewName(String s, Locale locale) throws Exception {
            return null;
        }
    }
}

在springboot中,有非常多的xxxxAutoConfiguration帮助我们进行扩展配置,只要看见了这个东西,我们就要注意了

4、首页配置

1.首页配置:

​ 1.注意点,所有页面的静态资源都需要使用thmeleaf来接管;

​ 2.url: @{}

2.页面国际化:

​ 1.我们需要配置i18n文件

​ 2.我们如果需要在项目中进行自动切换,我们需要自定义一个组件LocaleResolver

​ 3.记得将自己写的组件配置到Spring容器 @Bean

4.  #{}

5、登录功能实现

1.通过thymeleaf和index.html进行绑定

2.编写LoginController

@Controller
public class LoginController {
    @RequestMapping("/user/login")
    public String login(@RequestParam("username") String username,
                        @RequestParam("password") String password,
                        Model model, HttpSession session){

        //具体的业务:
        if(!StringUtils.isEmpty(username) && "123456".equals(password)){
            session.setAttribute("loginUser",username);
            return "redirect:/main.html";
        } else {
            //告诉用户你登录失败了
            model.addAttribute("msg","用户名或者密码错误");
            return "index";
        }
    }
}

3.实现中英文界面切换

public class MyLocaleResolver implements LocaleResolver {

    //解析请求
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        String language = request.getParameter("l");

        Locale locale = Locale.getDefault();//如果没有就是用默认

        //如果请求的连接携带了地区化的参数
        if(!StringUtils.isEmpty(language)){
            //zh_CN
            String[] split = language.split("_");
            //国家,地区
            locale = new Locale(split[0], split[1]);

        }

        return locale;
    }
}    

JavaConfig里添加bean

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

4.添加登录过滤器

public class LoginHandlerInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //登录成功之后,应该有用户的session

        Object loginUser = request.getSession().getAttribute("loginUser");
        if(loginUser==null){//没有登录
            request.setAttribute("msg","没有权限,请先登录");
            request.getRequestDispatcher("/index.html").forward(request,response);
            return false;
        }else {
            return true;
        }
    }
}

编写完过滤器 要记得在JavaConfig类中添加重写方法

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

6、增删改查–员工列表展示

1.提取公共页面

  1. th:fragment=“sidebar”

  2. th:replace="~{commons/commons::sidebar}

  3. 如果要传递参数,可以直接使用()传参,接收判断即可

th:class="${active=='main.html'?'nav-link active':'nav-link'}"

2.列表循环展示

<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>[[${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(),'yyyy-MM-dd HH:mm:ss')}"></td>
      <td>
         <button class="btn btn-sm btn-primary">编辑</button>
         <button class="btn btn-sm btn-danger">删除</button>
      </td>
   </tr>

</tbody>

7、添加员工

1.按钮提交

<h2><a class="btn btn-sm btn-success" th:href="@{/emp}">添加员工</a></h2>

2.跳转到页面

@GetMapping("/emp")
public String toAddpage(Model model){

    //查出所有部门的信息
    Collection<Department> departments = departmentDao.getDepartments();
    model.addAttribute("departments",departments);
    return "emp/add";
}

3.添加员工成功

html创建一个add.html的添加页面 表格模式

<form th:action="@{/emp}" method="post">
    <div class="form-group">
        <label>LastName</label>
        <input type="text" name="lastName" class="form-control" placeholder="海绵宝宝">
    </div>
    <div class="form-group">
        <label>Email</label>
        <input type="email" name="email" class="form-control" placeholder="1176244270@qq.com">
    </div>
    <div class="form-group">
        <label>Gender</label><br>
        <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 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>
    <div class="form-group">
        <label>department</label>
        <!--我们在controller接受的是一个employee,所以我们需要提交的其中的一个属性-->
        <select class="form-control" name="department.id">
            <option th:each="dept:${departments}" th:text="${dept.getDepartmentName()}" th:value="${dept.getId()}"></option>

        </select>
    </div>
    <div class="form-group">
        <label>Birth</label>
        <input type="text" name="birth" class="form-control" placeholder="嘤嘤嘤">
    </div>
    <button type="submit" class="btn btn-primary">添加</button>
</form>

4.返回首页

@PostMapping("/emp")
public String toEmp(Employee employee){
    System.out.println("save=>"+employee);
    employeeDao.save(employee);//调用底层业务的方法保存员工的信息

    //添加的操作 forward
    return "redirect:/emps";
}

8、修改和删除员工

//去员工的修改页面
@GetMapping("/emp/{id}")
public String toUpdateEmp(@PathVariable("id")Integer id,Model model){
    //查出原来的数据
    Employee employee = employeeDao.getEmployeeById(id);
    model.addAttribute("emp",employee);
    //查出所有部门的信息
    Collection<Department> departments = departmentDao.getDepartments();
    model.addAttribute("departments",departments);
    return "emp/update";
}

@PostMapping("/updateEmp")
public String updateEmp(Employee employee){
    employeeDao.save(employee);
    return "redirect:/emps";
}
@GetMapping("/delEmp/{id}")
public String deleteEmp(@PathVariable("id")int id){
    employeeDao.delete(id);
    return "redirect:/emps";
}

9、404页面

只需要在templates中创建一个error文件夹,把404.html丢进去即可

记得修改路径!去掉static

在这里插入图片描述

10、注销功能

在这里插入图片描述

@RequestMapping("/user/logout")
public String logout(HttpSession session){
    session.invalidate();
    return "redirect:/index.html";
}

11、前端

  • 模板:别人写好的,我们拿来改成自己需要的
  • 框架:组件,自己手动组合拼接! BootStrap layUI semantic-UI
    • 栅格系统
    • 导航栏
    • 侧边栏
    • 表单

如何快速搭建web应用?

  • 前端搞定:页面长什么样子:数据
  • 设计数据库
  • 前端让他能够自动运行,独立化工程
  • 数据接口如何对接:json,对象 all in one
  • 前后端联调测试

1.有一套自己熟悉的后台模板:工作必要!x-admin

2.前端界面:至少自己能够通过前端框架,组合出来一个网站页面

  • index
  • about
  • blog
  • post
  • user

3.让这个网站能够独立运行!

结合JDBC

  • springboot是什么?

  • 微服务

  • 写出第一个hello world

  • 探究源码~得出自动装配原理

  • 配置 yaml

  • 多文档环境切换

  • 静态资源映射

  • Thymeleaf th:xxx

  • springboot如何扩展mvc javaConfig

  • 如何修改springboot的默认配置

  • CRUD

  • 国际化

  • 拦截器

  • 定制首页,错误页

这次:

  • JDBC
  • Mybatis:重点
  • Druid:重点
  • Shiro:安全 重点
  • Spring Security:安全 重点
  • 异步任务,邮件发送,定时任务
  • Swagger
  • Dubbo+Zeekooper

Data

结合spring

1、创建项目,勾选jdbc相关配置

<!--JDBC-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<!--MySQL-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>

2、用yaml配置jdbc的连接参数

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&charsetEncoding=UTF-8
    driver-class-name: com.mysql.cj.jdbc.Driver

3、连接数据库

4、创建controller测试数据

@RestController
public class JDBCController {

    @Autowired
    JdbcTemplate jdbcTemplate;

    //查询数据库的所有信息
    //没有实体类,数据库的东西,
    @GetMapping("/userlist")
    public List<Map<String,Object>> ueserList(){
        String sql = "select * from user";
        List<Map<String, Object>> list_maps = jdbcTemplate.queryForList(sql);

        return list_maps;
    }

    @GetMapping("/addUser")
    public String addUser(){
        String sql = "insert into mybatis.user(id,name,pwd) value (10,'小牛','1234156')";
        jdbcTemplate.update(sql);
        return "update-ok";
    }


    @GetMapping("/updateUser/{id}")
    public String updateUser(@PathVariable("id")int id){
        String sql = "update mybatis.user set name=?,pwd=? where id="+id;
        //封装
        Object[] objects = new Object[2];
        objects[0]="小明2";
        objects[1]="zzzzzzz";
        jdbcTemplate.update(sql,objects);
        return "update-ok";
    }

    @GetMapping("/deleteUser/{id}")
    public String deleteUser(@PathVariable("id")int id){
        String sql = "delete from mybatis.user where id=?";
        jdbcTemplate.update(sql,id);
        return "delete-ok";
    }

}

6、配置Druid

​ 1.添加依赖

<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.3</version>
</dependency>

​ 2.配置里添加参数

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&charsetEncoding=UTF-8
    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.创一个config文件夹存放DruidConfig类

@Configuration
public class DruidConfig {
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druidDataSource(){
        return new DruidDataSource();
    }
    //后台监控:web.xml,ServletRegistrationBean
    //应为SpringBoot内置了servlet容器,所以没有web.xml 替代方法:ServletRegistrationBean
    @Bean
    public ServletRegistrationBean statViewServlet(){
        ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
        //后台需要有人登陆,配置账号密码
        HashMap<String,String> initParameters = new HashMap<>();
        //增加配置
        initParameters.put("loginUsername","admin");//登陆key 是固定的 loginUsername loginPassword
        initParameters.put("loginPassword","123456");
        //允许谁可以访问
        initParameters.put("allow","");
        //禁止谁能访问
        //initParameters.put("xiaomi","192.168.11.123");
        bean.setInitParameters(initParameters);//设置初始化参数
        return bean;
    }
    //filter
    @Bean
    public FilterRegistrationBean webStatFilter(){
        FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new WebStatFilter());
        //可以过滤哪些请求呢
        Map<String, String> initParameters = new HashMap<>();
        initParameters.put("exclusions","*.js,*.css,/druid/*");
        bean.setInitParameters(initParameters);
        return bean;
    }
}

Mybatis

整合包

mybatis-spring-boot-start

1.导入包

<!--mybatis-spring-boot-starter整合-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>

2.配置文件

spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 整合mybatis
mybatis.type-aliases-package=com.mi.pojo
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml

3.mybatis配置(UserMapper.xml)

4.编写sql

<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.mi.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, pwd) VALUES (#{id},#{name},#{pwd})
    </insert>

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

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

5.编写接口和User类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private int id;
    private String name;
    private String pwd;
}
@Mapper
@Repository
public interface UserMapper {

    List<User> queryUserList();

    User queryUserById(int id);

    int addUser(User user);

    int updateUser(User user);

    int deleteUser(int id);
}

6.service层调用dao层

7.controller调用service层

@RestController
public class UserController {

    @Autowired
    private UserMapper userMapper;

    @GetMapping("/queryUserList")
    public List<User> queryUserList(){
        List<User> userList = userMapper.queryUserList();
        for (User user : userList) {
            System.out.println(user);
        }

        return userList;
    }

    //添加一个用户
    @GetMapping("/addUser")
    public String addUser(){
        userMapper.addUser(new User(10,"小小米","159753"));
        return "ok";

    }
    //修改一个用户
    @GetMapping("/updateUser")
    public String updateUser(){
        userMapper.updateUser(new User(10,"小小米","798765465"));
        return "ok";
    }
    //根据id删除用户
    @GetMapping("/deleteUser")
    public String deleteUser(){
        userMapper.deleteUser(10);
        return "ok";
    }
}

M:数据和业务

C:交接

V:HTML

Swagger

学习目标:

  • 了解Swagger的作用和概念
  • 了解前后端分离
  • 在springboot中集成swagger

前后端分离

Vue+SpringBoot

后端时代:前端使用管理静态页面;html==>后端。模板引擎JSP=>后端是主力

前后端分离时代:

  • 后端:后端控制层,服务层,数据访问层【后端团队】
  • 前端:前端控制层,视图层【前端团队】
    • 伪造后端数据,json。已经存在,不需要后端,前端工程依旧能够跑起来
  • 前后端如何交互====> API
  • 前后端相对独立,松耦合
  • 前后端甚至可以部署在不同的服务器上

产生的一个问题:

  • 前后端继承联调,前端人员和后端人员无法做到,即使协商,尽早解决

解决方案:

  • 首先指定schema[计划的提纲],实时更新最新的API,降低集成的风险;
  • 早些年:制定word计划文档;
  • 前后端分离:
    • 前端测试后端接口:postman
    • 后端提供接口,需要实时更新最新的消息改动!

Swagger

  • 号称世界上最流行的API框架
  • RestFul Api文档在线自动生成工具=>Api文档与Api定义同步更新
  • 直接运行,可以在线测试API接口
  • 支持多种语言:(java,Php)

官网:https://swagger.io/

在项目使用swagger需要springbox

  • swagger2
  • ui

SpringBoot继承swagger

1.新建一个SpringBoot - web项目

2.导入相关依赖

<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>3.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>3.0.0</version>
</dependency>
3.0还需要配置
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>

3.编写一个hello工程

4.配置Swagger==>Config

@Configuration
@EnableSwagger2 //开启swagger2
public class SwaggerConfig {
}

5.测试运行:3.0为:http://localhost:8080/swagger-ui/index.html

Swagger配置扫描接口

Docket.select()

//配置了Swagger的Docket的bean实例
//enable是否启动swagger,如果为False则Swagger不能在浏览器访问
@Bean
public Docket docket(){
    return new Docket(DocumentationType.SWAGGER_2)
            .apiInfo(apiInfo())
            .select()
            //RequestHandlerSelectors,配置要扫描接口的方式
            //basePackage:指定要扫描的包
            //any():扫描全部
            //none():不扫描
            //.withClassAnnotation():扫描类上的注解
            //.withMethodAnnotation():扫描方法上的注解
            .apis(RequestHandlerSelectors.basePackage("com.mi.controller"))
            //paths()过滤什么路径
            /*.paths(PathSelectors.ant("/mi/**"))*/
            .build();
}

我只希望我的Swagger在生产环境中使用,在发布的时候不使用?

  • 判断是不是生产环境 flag=false
  • 注入enable(flag)

配置API文档的分组

.groupName("小米")

配置多个分组;多个Docket实例即可

@Bean
public Docket docket1(){
    return new Docket(DocumentationType.SWAGGER_2).groupName("A");
}
@Bean
public Docket docket2(){
    return new Docket(DocumentationType.SWAGGER_2).groupName("B");
}
@Bean
public Docket docket3(){
    return new Docket(DocumentationType.SWAGGER_2).groupName("C");
}

实体类

@ApiModel("用户实体类")
public class User {

    @ApiModelProperty("用户名")
    public String username;
    @ApiModelProperty("密码")
    public String password;
}

控制类

GetMapping(value = "/hello")
public String hello(){
    return "hello";
}


//只要我们的接口中,返回值存在实体类,他就会被扫描到
@PostMapping(value = "/user")
public User user(){
    return new User();
}

@ApiOperation("hello控制类")
@GetMapping(value = "/hello2")
public String hello(@ApiParam("用户名") String username){
    return "hello"+username;
}


@ApiOperation("Post测试类")
@PostMapping(value = "/postt")
public User postt(@ApiParam("用户名")User user){
    int i=5/0;
    return user;
}

总结:

1.我们可以通过Swagger给一些比较难理解的属性或者接口,增加注释信息

2.接口文档实时更新

3.可以在线测试

Swagger是一个优秀的工具,几乎所有大公司都在使用它

【注意点】在正式发布的时候,关闭Swagger!出于安全考虑,而且节省运行的内存;

任务

异步任务~

@Service
public class AsyncService {

    //告诉Spring这是一个异步的方法
    @Async
    public void hello(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("数据正在处理。。。");
    }
}

定时任务~

@Service
public class ScheduledService {

    //在一个特定的时间执行这个方法~ Timer

    /*
        0 54 11 * * ? 每天10点15分30 执行一次
        30 0/5 10,18 * * ? 每天10点和18点,每隔五分钟执行一次

        0 15 10 ? * 1-6 每个月的周一到周六 10.15分钟执行一次
     */


    //cron 表达式
    //秒 分 时 日 月 周几
    @Scheduled(cron = "0 54 11 * * ?")
    public void hello(){
        System.out.println("hello,你被执行了~");
    }
}

邮件任务~

@Autowired
JavaMailSenderImpl mailSender;
@Test
void contextLoads() {

    //一个简单的邮件
    SimpleMailMessage mailMessage = new SimpleMailMessage();
    mailMessage.setSubject("美好的事情即将发生");
    mailMessage.setText("谢谢你的狂神说java系列课程");

    mailMessage.setTo("437078164@qq.com");
    mailMessage.setFrom("15540974485@163.com");

    mailSender.send(mailMessage);

}

@Test
void contextLoads2() throws MessagingException {

    //一个复杂的邮件
    MimeMessage mimeMessage = mailSender.createMimeMessage();
    //组装
    MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);

    helper.setSubject("小米你好呀~plus");
    helper.setText("<p style='color:red'>谢谢你的狂神说Java系列课程~</p>",true);

    //附件
    helper.addAttachment("1.jpg",new File("C:\\Users\\xiaososa\\Desktop\\1.jpg"));
    helper.addAttachment("2.jpg",new File("C:\\Users\\xiaososa\\Desktop\\1.jpg"));

    helper.setTo("437078164@qq.com");
    helper.setFrom("15540974485@163.com");

    mailSender.send(mimeMessage);

}

/**
 *
 * @param html
 * @param subject
 * @param text
 * @throws MessagingException
 */
public void sendMail(boolean html,String subject,String text) throws MessagingException {
    //一个复杂的邮件
    MimeMessage mimeMessage = mailSender.createMimeMessage();
    //组装
    MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true);

    helper.setSubject(subject);
    helper.setText(text,true);

    //附件
    helper.addAttachment("1.jpg",new File("C:\\Users\\xiaososa\\Desktop\\1.jpg"));
    helper.addAttachment("2.jpg",new File("C:\\Users\\xiaososa\\Desktop\\1.jpg"));

    helper.setTo("437078164@qq.com");
    helper.setFrom("15540974485@163.com");

    mailSender.send(mimeMessage);

}
TaskScheduler 任务调度者
TaskExecutor 任务执行者

@EnableScheduling//开启定时功能的注解
@Scheduled//什么时候执行~

Cron表达式

Redis+SpringBoot整合

SpringBoot操作数据:spring-data jpa jdbc mongodb redis!

SpringData也是和SpringBoot齐名的项目

说明:在SpringBoot2.x之后,原来使用的jedis被替换为lettuce?

jedis:采用的直连,多个线程操作的话,是不安全的,如果想要避免不安全的,使用jedis pool连接池,更像BIO模式

lettuce:采用netty,实例可以再多个线程中进行共享,不存在线程不安全的情况!可以减少线程数据了,更像NIO模式
源码分析:

@Bean
@ConditionalOnMissingBean(
    name = {"redisTemplate"}
)//我们可以自己定义一个RedisTemplate来替换这个默认的
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    //默认的RedisTemplate没有过多的设置,redis对象都是需要序列化
    //两个泛型都是Object,Object的类型,我们需要强制转换<String,Object>
    RedisTemplate<Object, Object> template = new RedisTemplate();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
}

@Bean
@ConditionalOnMissingBean//由于String是redis中最常使用的类型,所以说单独提取出来一个bean
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
    StringRedisTemplate template = new StringRedisTemplate();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
}

整合测试一下

1、导入依赖

<!--操作redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2、配置连接

# 配置redis
spring.redis.host=127.0.0.1
spring.redis.port=6379

3、测试

@SpringBootTest
class Redis02SpringbootApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {

        //redisTemplate 操作不同的数据类型 api和我们的指令是一样的
        //opsForValue 操作字符串类 类似String
        //opsForList 操作List 类似List
        //opsForSet
        //opsForHash
        //opsForGeo
        //opsForZSet
        //opsForHyperLogLog

        //除了基本的操作,我们常用的方法都可以直接通过redisTemplate操作
        //比如基本的事务和CRUD

        //获取redis的连接对象
        //RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        //connection.flushDb();
        //connection.flushAll();
        redisTemplate.opsForValue().set("mykey","xiaomi");
        System.out.println(redisTemplate.opsForValue().get("mykey"));

    }

}

关于对象的保存:

在这里插入图片描述

我们来自己编写一个RedisTemplate

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        //我们为了自己开发方便一般直接使用<String,Object>
        // 将template 泛型设置为 <String, Object>
        RedisTemplate<String, Object> template = new RedisTemplate();
        // 连接工厂,不必修改
        template.setConnectionFactory(redisConnectionFactory);
        /*
         * 序列化设置
         */
        // key、hash的key 采用 String序列化方式
        template.setKeySerializer(RedisSerializer.string());
        template.setHashKeySerializer(RedisSerializer.string());
        // value、hash的value 采用 Jackson 序列化方式
        template.setValueSerializer(RedisSerializer.json());
        template.setHashValueSerializer(RedisSerializer.json());
        template.afterPropertiesSet();

        return template;
    }
}

所有的redis操作,其实对于java开发人员来说,十分的简单,更重要的是理解redis的思想和每一种数据结构的用处和作用场景!

分布式Dubbo+Zookeeper+SpringBoot

HTTP SpringCloud(生态)

RPC两个核心模块:通讯、序列化

序列化:数据传输需要转换

Netty:30天~

Dubbo~18年重启! Dubbo 3.x RPC Error Exception

专业的事,交给专业的人来做~

步骤:

1、提供者提供服务

1、导入相关依赖

<!--导入依赖:Dubbo+zookeeper-->
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-spring-boot-starter</artifactId>
    <version>2.7.8</version>
</dependency>
<!--zkclient-->
<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
<dependency>
    <groupId>com.github.sgroschupf</groupId>
    <artifactId>zkclient</artifactId>
    <version>0.1</version>
</dependency>
<!--日志会冲突-->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>5.1.0</version>
</dependency>
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>5.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.6.2</version>
    <exclusions>
        <exclusion>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
    </exclusions>
</dependency>

2、配置注册中心的地址,以及服务发现名,和要扫描的包

#服务应用名字
dubbo.application.name=provider-server
#注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
#哪些服务要被注册
dubbo.scan.base-packages=com.mi.service

3.在想要被注册的服务上面~增加一个注解@Service

2、消费者如何消费

1.导入依赖

2.配置注册中心的地址,配置自己的服务名

3.远程注入服务

聊聊现在和未来

回顾以前,架构

三层架构  + MVC
	架构 ---> 解耦

开发框架
	Spring
        IOC AOP
        	IOC:控制反转
        		约泡:
        			泡温泉,泡茶。。。。泡友
        			附近的人,打招呼,加微信,聊天-------->约泡
        		浴场:温泉,茶庄,泡友
                	直接进温泉,就有人和你一起了
                	
                原来我们都是自己一步步操作,现在交给容器了,我们需要什么就去拿就可以了	
                
            AOP:面向切面编程 (本质,动态代理)
            
            	为了解决什么?不影响业务本来的情况下,实现动态增加功能,大量应用在日志,事务...等等方面
        Spring是一个轻量级的java开源框架,容器
        目的:解决企业开发的复杂性问题
        Spring是春天,觉得他是春天,也十分复杂,配置文件
	
	SpringBoot
		SpringBoot并不是新东西,就是Spring的升级版!
		新一代JavaEE的开发标准,开箱即用!->拿过来就可以用!
		它自动帮我们配置了非常多的东西,我们拿来即用!
		特性:约定大于配置
		
随着公司的体系越来越大,用户越来越多

微服务架构--->新架构
	模块化,功能化!
	用户模块,支付模块,签到模块,娱乐模块
	人过于多:一台服务器解决不了;再增加服务器!横向
	假设A服务器占用98%资源,B服务器只占用了10%。---负载均衡;
	
	将原来的整体项目,分成模块化,用户就是一个单独的项目,签到也是一个单独的项目,项目和项目之间需要通信,如何通信?
	用户非常多,而签到十分少! 给用户多一点服务器,给签到少一点服务器!

微服务架构问题?
	分布式架构会遇到的四个核心问题?
	1. 这么多服务,客户端该如何去访问?
	2. 这么多服务,服务之间如何进行通信?
	3. 这么多服务,如何治理呢?
	4. 服务挂了,怎么办?
	
解决方案:
	SpringCloud,是一套生态,就是解决以上分布架构的4个问题
	想使用SpringCloud,必须掌握SpringBoot,因为SpringCloud是基于SpringBoot;
	
	1.Spring Cloud Netflix,出来了一套解决方案
		Api网关,zuul组件
		Feign--->HttpClient--->HTTP的通信方式,同步并阻塞
		服务注册与发现,Eureka
		熔断机制,Hystrix
		
		2018年年底,Netflix宣布无限期停止维护。生态不再维护,就会脱节。
	
    2.Apache Dubbo zookeeper,第二套解决系统
    	Api:没有!要么找第三方插件,要么自己实现
    	Dubbo是一个高性能的基于Java实现的,RPC通信框架!
    	服务注册与发现,zookeeper:动物园管理者(Hadoop,Hive)
    	没有:借助了Hystrix
    	
    	不完善,Dubbo
    	
    3. SpringCloud Alibaba 一站式解决方案	
    
目前,又提出了一种方案:
	服务网格:下一代微服务标准。Server Mesh
	代表解决方案:Istio
	
万变不离其宗,一通百通	
	1.API网关,服务路由
	2.HTTP,RPC框架,异步调用
	3.服务注册与发现,高可用
	4.熔断机制,服务降级
	
如果,你们基于这四个问题,开发一套解决方案,也叫SpringCloud!

为什么要解决这个问题?本质:网络不可靠

程序员,不能停下学习的脚步
	

回顾以前,架构

三层架构  + MVC
	架构 ---> 解耦

开发框架
	Spring
        IOC AOP
        	IOC:控制反转
        		约泡:
        			泡温泉,泡茶。。。。泡友
        			附近的人,打招呼,加微信,聊天-------->约泡
        		浴场:温泉,茶庄,泡友
                	直接进温泉,就有人和你一起了
                	
                原来我们都是自己一步步操作,现在交给容器了,我们需要什么就去拿就可以了	
                
            AOP:面向切面编程 (本质,动态代理)
            
            	为了解决什么?不影响业务本来的情况下,实现动态增加功能,大量应用在日志,事务...等等方面
        Spring是一个轻量级的java开源框架,容器
        目的:解决企业开发的复杂性问题
        Spring是春天,觉得他是春天,也十分复杂,配置文件
	
	SpringBoot
		SpringBoot并不是新东西,就是Spring的升级版!
		新一代JavaEE的开发标准,开箱即用!->拿过来就可以用!
		它自动帮我们配置了非常多的东西,我们拿来即用!
		特性:约定大于配置
		
随着公司的体系越来越大,用户越来越多

微服务架构--->新架构
	模块化,功能化!
	用户模块,支付模块,签到模块,娱乐模块
	人过于多:一台服务器解决不了;再增加服务器!横向
	假设A服务器占用98%资源,B服务器只占用了10%。---负载均衡;
	
	将原来的整体项目,分成模块化,用户就是一个单独的项目,签到也是一个单独的项目,项目和项目之间需要通信,如何通信?
	用户非常多,而签到十分少! 给用户多一点服务器,给签到少一点服务器!

微服务架构问题?
	分布式架构会遇到的四个核心问题?
	1. 这么多服务,客户端该如何去访问?
	2. 这么多服务,服务之间如何进行通信?
	3. 这么多服务,如何治理呢?
	4. 服务挂了,怎么办?
	
解决方案:
	SpringCloud,是一套生态,就是解决以上分布架构的4个问题
	想使用SpringCloud,必须掌握SpringBoot,因为SpringCloud是基于SpringBoot;
	
	1.Spring Cloud Netflix,出来了一套解决方案
		Api网关,zuul组件
		Feign--->HttpClient--->HTTP的通信方式,同步并阻塞
		服务注册与发现,Eureka
		熔断机制,Hystrix
		
		2018年年底,Netflix宣布无限期停止维护。生态不再维护,就会脱节。
	
    2.Apache Dubbo zookeeper,第二套解决系统
    	Api:没有!要么找第三方插件,要么自己实现
    	Dubbo是一个高性能的基于Java实现的,RPC通信框架!
    	服务注册与发现,zookeeper:动物园管理者(Hadoop,Hive)
    	没有:借助了Hystrix
    	
    	不完善,Dubbo
    	
    3. SpringCloud Alibaba 一站式解决方案	
    
目前,又提出了一种方案:
	服务网格:下一代微服务标准。Server Mesh
	代表解决方案:Istio
	
万变不离其宗,一通百通	
	1.API网关,服务路由
	2.HTTP,RPC框架,异步调用
	3.服务注册与发现,高可用
	4.熔断机制,服务降级
	
如果,你们基于这四个问题,开发一套解决方案,也叫SpringCloud!

为什么要解决这个问题?本质:网络不可靠

程序员,不能停下学习的脚步
	

转自狂神

B站地址:https://space.bilibili.com/95256449

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShyTan

喜欢的给点打赏呗,纯手打

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值