微服务阶段
javase:OOP
mysql:持久化
html+css+jquery+框架:视图,框架,css
javaweb:独立开发MVC三层架构的安慰你观战了:原始
ssm:框架:简化了我们的开发流程,配置也开始较为复杂
war:tomcat运行
spring再简化:SpringBoot-jar,内嵌Tomcat
来来来,给自己一个规划
SpringBoot:快速入门
什么是Spring
Spring是如何简化Java开发的
什么是SpringBoot
约定大于配置!!!约定大于配置!!!约定大于配置!!!
Spring Boot的主要优点:
给自己定目标是:
程序=数据结构 + 算法=>程序员
不要关注的是:
程序=面向对象 + 框架=>码农
微服务
什么是微服务?
单体应用架构
微服务架构
如何构建微服务
第一个SpringBoot程序
到底多么简单:
- jdk1.8
- maven 3.6.1
- springBoot最新版
- IDEA
官方:提供了一个快速生成的网站!IDEA继承了这个网站
-
可以在官网直接下载后,导入idea开发,(快速开始里面)
-
直接使用idea创建一个springboot项目(一般开发直接在idea中创建)
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
原理初探
自动配置:
pom.xml
- spring-boot-dependencies:核心依赖在父工程中!
- 我们在写或者引入一些Springboot依赖的时候,不需要指定版本,就因为有这些版本仓库
启动器
-
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency>
-
启动器:说白了就是Springboot的启动场景
-
比如spring-boot-starter-web,他就会帮我们自动导入web环境所有的依赖!
-
springboot会将所有的功能场景,都变成一个一个的启动器
-
我们要使用什么功能,就只需要找到对应的启动器就可以了 starter
主程序
//@SpringBootApplication:标注这个类是一个springboot的应用
@SpringBootApplication
public class Spingboot01Application {
public static void main(String[] args) {
//将springboot应用启动
SpringApplication.run(Spingboot01Application.class, args);
}
}
-
注释
-
@SpringBootConfiguration : springboot的配置 @Documented:spring的配置类 @Configuration:说明这也是一个spring的组件 @EnableAutoConfiguration:自动配置 @AutoConfigurationPackage:自动配置包 @Import(AutoConfigurationPackages.Registrar.class):导入选择器 包注册 @Import(AutoConfigurationImportSelector.class):自动导入选择器 //获取所有的配置 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
-
获取候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
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;
}
META-INF/spring-factories:自动配置的核心文件
结论:springboot所有自动配置都是在启动的时候扫描并加载:spring,factories所有的自动配置类都在这里面,但是不一定生效,要判断条件是非成立,只要导入了对应的start,就有对应的启动器了,有了启动器,我们自动装配就会生效,然后就配置成功!
Run
SpringApplication
spingboot的配置
YAML
YAML语法
#k=v
#对空格的要求十分高
#普通的key-value
name: ljh
#对象
student:
name: ljh
age: 3
#行内写法
student: {name: ljh,age: 3}
#数组
pets:
- cat
- dog
- pig
pets: [cat,dog,pig]
对比properties
#properties只能保存键值对
name=ljh
student.name=ljh
student.age=3
yaml可以直接给实体类赋值
点开提示会有官方叫你加依赖,那就加吧!
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
加了不爆红了
上代码:
Person.java
package com.ljh.pojo;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
@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> lists;
private Dog dog;
public Person() {
}
public Person(String name, Integer age, Boolean happy, Date birth, Map<String, Object> map, List<Object> lists, Dog dog) {
this.name = name;
this.age = age;
this.happy = happy;
this.birth = birth;
this.map = map;
this.lists = lists;
this.dog = dog;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Boolean getHappy() {
return happy;
}
public void setHappy(Boolean happy) {
this.happy = happy;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public Map<String, Object> getMap() {
return map;
}
public void setMap(Map<String, Object> map) {
this.map = map;
}
public List<Object> getLists() {
return lists;
}
public void setLists(List<Object> lists) {
this.lists = lists;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", happy=" + happy +
", birth=" + birth +
", map=" + map +
", lists=" + lists +
", dog=" + dog +
'}';
}
}
Dog.java
package com.ljh.pojo;
import org.springframework.stereotype.Component;
@Component
public class Dog {
private String name;
private Integer age;
public Dog() {
}
public Dog(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试:
package com.ljh;
import com.ljh.pojo.Dog;
import com.ljh.pojo.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class Springboot02ConfigApplicationTests {
@Autowired
Person person = new Person();
@Test
void contextLoads() {
System.out.println(person);
}
}
配置文件:application.yaml
sever:
port: 8087
Person:
name: ljh
age: 3
happy: false
birth: 2019/11/02
map: {k1: v1,k2: v2}
list:
- code
- music
- girl
dog:
name: 旺财
age: 3
输出结果:
Person{name=‘ljh’, age=3, happy=false, birth=Sat Nov 02 00:00:00 CST 2019, map={k1=v1, k2=v2}, lists=null, dog=Dog{name=‘旺财’, age=3}}
yaml的灵活性
sever:
port: 8087
Person:
name: ljh${random.uuid}
age: ${random.int}
happy: false
birth: 2019/11/02
map: {k1: v1,k2: v2}
list:
- code
- music
- girl
dog:
#存在就person.hello,不存在就hello
name: ${person.hello:hello}_旺财
age: 3
唠两句
properties的配置解决乱码,先把它配了再说
@Value是针对properties配置的,可以发现yaml强大多了,propertis使用起来并不友好,需要为每个单独注解赋值,比较麻烦。
//javaConfig绑定我们配置文件的值,可以采取这种方式
//加载指定的配置文件
//@PropertySource("classpath:ljh.properties")
public class Person {
松散绑定:就是这样
dog:
first-name: 大黄
age: 3
@Component
@ConfigurationProperties(prefix = "dog")
public class Dog {
private String firstName;
private Integer age;
输出结果:
如果手动改,记得getter和setter方法名一起改哟,不然不会生效的
JSR303数据校验
@Component
@ConfigurationProperties(prefix = "person")
//javaConfig绑定我们配置文件的值,可以采取这种方式
//加载指定的配置文件
//@PropertySource("classpath:ljh.properties")
@Validated//数据校验
public class Person {
@Email(message = "邮箱格式错误")
多环境配置及配置文件位置
四个位置:优先级
优先级如图,默认是最低的,可以写不一样的端口号来测
多环境切换
注意,前面都用application-xx
看yaml的写法,明显优势,多块文档
自动配置原理再理解
#配置文件到底能写什么?---联系--和spring.factories
#在我们这配置文件中能配置的东西,都存在一个固有的规律
#xxxAutoConfiguration:默认值 xxxProperties和配置文件绑定,我们就可以使用自定义的配置了
#通过debug: true来查看,哪些自动配置类,哪些没有生效
debug: true
实例:
随便写一个,ctrl点击,broker-url进入:
然后我们定位去找jar包下面的类,或者ctrl点类名
第一个就是自动装配类
或者这样去找,避免找错
发现有红色,没生效,需要添加依赖,(怎么加,找对应的启动器,加载pom文件中),
果然,看debug: true打印的日志能发现没生效,因为缺少依赖
@Conditional
SpringBoot Web开发
jar: webapp!
自动装配
springboot到底帮我们配置了什么?我们能不能进行修改?能修改哪些东西?能不能扩展?
- xxxAutoConfiguration向容器中自动配置组件
- xxxProperties:自动配置类,装配配置文件中自定义的一些内容!
要解决的问题:
- 导入静态资源
- 首页
- jsp,模板引擎Thymeleaf
- 装配扩展SpringMVC
- 增删改查
- 拦截器
- 国际化
静态资源
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//先判断在application.properties中是否配置
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);
registration.addResourceLocations(resource);
}
});
}
什么是webjars?
直接把jquery的maven放入pom.xml
第一种方式
第二种方式
我们可以增加
可以在文件夹中放入文件测试
自定义配置静态资源路径
首页
默认index.html
模板引擎
thymeleaf语法
MVC配置原理
修改SpringBoot的默认配置
方式一
package com.ljh.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Locale;
//如果,你向diy一些定制化的功能,只要写这个组件,然后将它交给springboot,springboot就会帮我们自动装配
//扩展springmvc dispatchservlet
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
//ViewResolver实现了视图解析器接口的类,我们就可以把他看做视图解析器
@Bean
public ViewResolver myviewResolver(){
return new MyviewResolver();
}
public static class MyviewResolver implements ViewResolver{
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
return null;
}
}
}
扩展使用SpringMVC
package com.ljh.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyMvcConfig1 implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/ljh").setViewName("test");
}
}
运行结果:
注意:
看到没,不要加@EnableWebMvc?是因为@Configuration里面
但是@EnableWebMvc里面继承了画红线这个类,炸裂
这告诉我们要看源码哟
页面国际化
上代码:
package com.ljh.config;
import org.springframework.web.servlet.LocaleResolver;
import org.thymeleaf.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;
public class MyLocaleResolver implements LocaleResolver {
//解析请求
@Override
public Locale resolveLocale(HttpServletRequest request) {
//获取请求中的语言参数
String language = request.getParameter("1");
Locale locale = Locale.getDefault();
//如果请求的链接携带了国际化的参数
if(!StringUtils.isEmpty(language)){
//zh_CN
String[] split = language.split("_");
//国家,地区
locale = new Locale(split[0],split[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}
- 404
Data
简介
上代码:
spring:
datasource:
url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8
password: 123456
username: root
driver-class-name: com.mysql.jdbc.Driver
package com.ljh.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
@RestController
public class JdbcController {
@Autowired
JdbcTemplate jdbcTemplate;
//查询数据库的所有信息
//没有实体类,数据库中的东西,怎么获取?
@RequestMapping("/userList")
public List<Map<String,Object>> userList(){
String sql = "select * from user";
List<Map<String, Object>> list = jdbcTemplate.queryForList(sql);
return list;
}
@RequestMapping("/addUser")
public String addUser(){
String sql = "insert into user(id,name,pwd) values (10,'kk','1234')";
jdbcTemplate.update(sql);
return "update-ok";
}
@RequestMapping("/updateUser/{id}")
public String updateUser(@PathVariable("id")int id){
String sql = "update user set name=?,pwd=? where id="+id;
//封装
Object[] o = new Object[2];
o[0] = "小明";
o[1] = "123456";
jdbcTemplate.update(sql,o);
return "update-ok";
}
@RequestMapping("/deleteUser/{id}")
public String deleteUser(@PathVariable("id")int id){
String sql = "delete from user where id="+id;
jdbcTemplate.update(sql,id);
return "update-ok";
}
}
上代码:
<!--Druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
package com.ljh.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
import javax.sql.DataSource;
import java.util.HashMap;
@Configuration
public class DuridConfig {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource duridDataSource(){
return new DruidDataSource();
}
@Bean
public ServletRegistrationBean a(){
ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet());
//后台需要有人登陆,账号密码配置
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("loginUsername","root");//登录的key是固定的loginUsername和loginPassword
hashMap.put("loginPassword","123456");
//允许谁可以访问
hashMap.put("allow","");
bean.setInitParameters(hashMap);//设置初始化参数
return bean;
}
//filter
@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean<Filter> bean = new FilterRegistrationBean<>();
bean.setFilter(new WebStatFilter());
//可以过滤哪些请求
HashMap<String, String> hashMap = new HashMap<>();
//这些东西不进行统计
hashMap.put("exclusions","*.js,*.css,/druid/*");//登录的key是固定的loginUsername和loginPassword
//允许谁可以访问
hashMap.put("allow","");
bean.setInitParameters(hashMap);//设置初始化参数
return bean;
}
}
Mybatis
整合包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
application.yaml
spring:
datasource:
url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8
password: 123456
username: root
driver-class-name: com.mysql.jdbc.Driver
#整合mybatis
mybatis:
type-aliases-package: com.ljh.pojo
mapper-locations: classpath:/mybatis/mapper/*.xml
代码:
User.java
package com.ljh.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private int id;
private String name;
private String pwd;
}
UserMapper
package com.ljh.mapper;
import com.ljh.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
//这个注解表示这是一个mybaatis的Mapper类:Dao
@Mapper
@Repository
public interface UserMapper {
List<User> queryUserList();
User queryUserById(int id);
}
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">
<!--nameSpace绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.ljh.mapper.UserMapper">
<select id="queryUserList" resultType="User">
select * from user
</select>
<select id="queryUserById" parameterType="int" resultType="User">
select * from user where id = #{id}
</select>
</mapper>
controller
package com.ljh.controller;
import com.ljh.mapper.UserMapper;
import com.ljh.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/queryUserList")
public List<User> queryUserList(){
List<User> list = userMapper.queryUserList();
for (User user : list) {
System.out.println(user);
}
return list;
}
}
项目结构:
SpringSecurity(安全)
在web开发中,安全第一位!过滤器,拦截器
功能性需求:否
做网站:安全应该在什么时候考虑?设计之初!
- 漏洞,隐私泄露
- 架构一旦确定
shiro,SpringSecurity:很像~除了类不一样,名字不一样;
认证,授权(vip1,vip2,vip3)
- 功能权限
- 访问权限
- 菜单权限
- 拦截器,过滤器:大量的原生代码冗余
MVCSPRINGSPRINGBOOT–架构思想
AOP:横切配置类
第一步:pom.xml
第二步:写配置类:认证和授权
补充完整,后面接.roles("**")
开启注销,记住我功能
第三步:controller
Shiro
代码过程:
可以去github下载下来,模仿着创建项目
-
依赖
-
配置文件shiro.ini(github里面拷贝)
-
quickStart
SpringBoot整合shiro
实现登录拦截
shiro实现用户认证
shiro整合Mybatis
shiro请求授权实现
增加字段perms
shiro整合Thymleaf
Swagger
Swagger简介
SpringBoot集成Swagger
配置Swagger
Swagger的bean实例Docket
Swagger配置扫描接口
Docket.select()
配置是否启动swagger
我只希望我的Swagger在生产环境中使用,在发布的时候不使用?
配置API文档的分组
实体类配置:
controller
任务
邮箱:
定时任务:
SpringBoot整合
一步一步来
新建项目:
自定义RedisTemplate
重复了@Autowrided不是我们的自定义怎么办
分布式Dubbo+Zookeeper+springBoot
步骤分析
RPC两个核心模块:通讯、序列化
Dubbo概念
zookeeper就是注册组件
zookeeper下载地址
安装完成
服务注册发现实例
依赖:
消费者依赖: