狂神SpringBoot教学笔记
微服务阶段javase:oopmysql:持久化html+css+js+jquery框架:视图,框架不熟练,css不好;javaweb:独立开发mvc三层架构的网站了,原始ssm:框架:简化了我们的开发流程,配置也开始较为复杂;war:tomcat运行spring再简化:SpringBoot-jar;内嵌tomcat;微服务架构服务越来越多:springcloud第一个SpringBoot程序jd
微服务阶段
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>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mQB9MnuL-1607052559645)(C:\Users\xiaososa\AppData\Roaming\Typora\typora-user-images\1606044583480.png)]
自动配置原理初探
自动配置:
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获取指定的值
- 将这些自动配置的类导入容器,自动配置就会生效,帮我进行自动配置
- 以前我们需要自动配置的东西,现在SpringBoot帮我们做了
- 整合javaEE,解决方案和自动配置的东西都在spring-boot-autoconfigure-2.4.0.jar这个包下
- 它会把所有需要导入的组件,以类名的方式返回,这些组件就会被添加到容器
- 容器中也会存在非常多的xxxAutoConfiguration的文件(@Bean),就是这类给容器中导入了这个场景需要的所有组件;并自动配置,@Configuration, JavaConfig!
- 有了自动配置类,免去了我们手动编写配置文件的工作!
SpringApplication原理初探
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9DeA1uHP-1607052559647)(C:\Users\xiaososa\AppData\Roaming\Typora\typora-user-images\1606050281381.png)]
关于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类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可;
xxxAutoConfiguration:自动配置类;给容器中添加组件
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.提取公共页面
-
th:fragment=“sidebar”
-
th:replace="~{commons/commons::sidebar}
-
如果要传递参数,可以直接使用
()
传参,接收判断即可 -
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!
为什么要解决这个问题?本质:网络不可靠
程序员,不能停下学习的脚步
更多推荐
所有评论(0)