什么是SpringBoot?
- Spring Boot 是由 Pivotal 团队提供的全新框架
- 目的是用来简化新 Spring 应用的初始搭建以及开发过程
- 该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置
- 通过这种方式,Spring Boot 致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。
- Spring Boot 并不是对 Spring 功能上的增强,而是提供了一种快速使用 Spring 的方式。
特性
- 约定大于配置
- 创建独立的spring应用程序。
- 嵌入的tomcat jetty 或者undertow 不用部署WAR文件。
- 允许通过Maven来根据需要获取starter
- 尽可能的使用自动配置spring
- 提供生产就绪功能,如指标,健康检查和外部配置properties yaml yml
- 开箱即用,没有代码生成,也无需 XML 配置,同时也可以修改默认值来满足特定的需求。
传统开发模式
-
优点
- 开发简单,集中式管理
- 基本不会重复开发
- 功能都在本地,没有分布式的管理和调用消耗
-
缺点
- 效率低:开发都在同一个项目改代码,相互等待,冲突不断
- 维护难:代码功功能耦合在一起,新人不知道何从下手
- 不灵活:构建时间长,任何小修改都要重构整个项目,耗时
- 稳定性差:一个微小的问题,都可能导致整个应用挂掉
- 扩展性不够:无法满足高并发下的业务需求
- 对服务器的性能要求要统一,要高
微服务开发模式
- 优点
- 每个微服务都很小,这样能聚焦一个指定的业务功能或业务需求
- 微服务能够被小团队开发,这个小团队2-5人就可以完成了
- 微服务是松耦合的,是有功能,有意义的服务,开发阶段或部署阶段都是独立的
- 微服务可以使用不同的语言开发
- 微服务能部署在中低端配置的服务器上
- 很容易和第三方集成
- 每个服务都有自己的存储能力,单独的库,也可以有统一的库
- 缺点:
- 微服务会带来过多的操作
- 可能有双倍的努力
- 分布式系统可能复杂难管理
- 分布跟踪部署难
- 当服务数量增加时,管理复杂度增加
SpringBoot的配置
配置文件
-
properties文件 #第一种配置文件
#mysql
jdbc.mysql.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.mysql.url=jdbc:mysql://localhost:3306/crm?serverTimezone=UTC
jdbc.mysql.username=root
jdbc.mysql.password=root
#druid
druid.initialSize=10
druid.minIdle=10
druid.maxActive=50
druid.maxWait=60000
yml文件
name: 张三
age: 10
birthday: 1998/07/25
gender: true
obj: ~
array1: [spring, springmvc, mybatis]
array2:
- html
- css
- javascript
student:
name: 李四
age: 22
birth: 1999/10/17
gender: false
hobby: [football, games, swimming]
address:
city: 郑州市
area: 金水区
street: 民航路
读取配置文件
-
本质是将配置类对象放到ioc容器中 -
单个读取 @Value("${name}")
private String username;
-
使用配置类读取
-
读取第三方的properties文件 @Component
@ConfigurationProperties(prefix = "jdbc.mysql")
@PropertySource(value = "classpath:db.properties")
-
读取原生的xml文件 -
demo
@RestController
public class ReadConfigController {
@Value("${name}")
private String username;
@Value("${age}")
private Integer age;
@Value("${birthday}")
private Date birthday;
@Value("${gender}")
private Boolean gender;
@Value("${student.name}")
private String studentName;
@GetMapping("/read")
public String read(){
return "姓名:" + username + " 年龄:" + age + " 生日:" + birthday + " 性别:" + gender + " 学生姓名:" + studentName;
}
@Autowired
private StudentProperties studentProperties;
@GetMapping("/readProperties")
public StudentProperties readProperties(){
return studentProperties;
}
@Autowired
private MysqlProperties mysqlProperties;
@GetMapping("/readProp")
public MysqlProperties readProp(){
return mysqlProperties;
}
@Autowired
private Emp emp;
@GetMapping("/readXml")
public Emp readXml(){
return emp;
}
}
在配置类上加注解
@ImportResource(locations = "classpath:applicationContext.xml")
@EnableConfigurationProperties({StudentProperties.class, AddressProperties.class})
@SpringBootApplication
public class Springboot02ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot02ConfigApplication.class, args);
}
}
读取yaml文件的配置类
@Data
@ConfigurationProperties(prefix = "student")
public class StudentProperties {
private String name;
private Integer age;
private Date birth;
private Boolean gender;
private String[] hobby;
private AddressProperties address;
}
@Data
@ConfigurationProperties(prefix = "student.address")
public class AddressProperties {
private String city;
private String area;
private String street;
}
读取properties文件的配置类
@Data
@Component
@ConfigurationProperties(prefix = "jdbc.mysql")
@PropertySource(value = "classpath:db.properties")
public class MysqlProperties {
private String driverClassName;
private String url;
private String username;
private String password;
}
读取原生的applicationContext.xml文件 <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dept" class="com.dx.bean.Dept">
<property name="id" value="10"/>
<property name="dname" value="研发部"/>
</bean>
<bean id="emp" class="com.dx.bean.Emp">
<property name="id" value="1001"/>
<property name="ename" value="汤姆"/>
<property name="dept" ref="dept"/>
</bean>
</beans>
@Data
public class Emp {
private Integer id;
private String ename;
private Dept dept;
}
@Data
@Accessors(chain = true)
public class Dept {
private Integer id;
private String dname;
}
profile配置文件
-
三种工作环境配置文件:开发环境(dev)、生产环境(prod)、测试环境(test)
server:
port: 8001
servlet:
context-path: /web-dev
server:
port: 8003
servlet:
context-path: /web-prod
server:
port: 8002
servlet:
context-path: /web-test
在测试的时候,需要修改pom的编译路径,确保把所有的配置文件都编译以后再测试 <build>
<resources>
<resource>
<directory>D:\workspace\SpringBoot-Code\02-spring-boot-config</directory>
<includes>
<include>**/*.yml</include>
<include>application.yml</include>
</includes>
</resource>
</resources>
</build>
部署时配置文件
-
外部配置文件 在D盘放一个application.yml文件 端口指定为8009
打包后使用命令行运行并且指定
java -jar aaa.jar --spring.config.location=D:/application.yml
-
命令修改配置文件 可以使用命令行参数指定(文档一行写不下的时候,不要回车)
java -jar aaa.jar --server.port=8888 --server.servlet.context-path=/bjpowernode
配置优先级
-
后加载的会覆盖先加载的 -
最后加载的优先级最高 -
spring boot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件 其中同一目标下的properties文件的优先级大于yml文件 -
配置文件可以放的位置和优先级 classpath:/ --优先级4 classpath:/config/ --优先级3 file:./ --优先级2 file:./config/ --优先级1
日志logback
配置日志级别
-
@RestController
public class LogController {
private Logger log = LoggerFactory.getLogger(LogController.class);
@GetMapping("/getLog")
public String getLog(){
log.error("error级别的日志");
log.warn("warn级别的日志");
log.info("info级别的日志");
log.debug("debug级别的日志");
log.trace("trace级别的日志");
log.info("无需重启自动生效...");
return "正在记录日志";
}
}
-
全局配置 局部配置
logging:
level:
root: info
com:
dx:
controller: trace
自定义日志输出格式
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss SSS} %-5level [%thread] %logger -- %msg%n"
生成日志文件
file:
name: demo.log
logback.xml:可以直接使用,直接放到项目中就可以
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="false" scanPeriod="60 seconds" debug="false">
<property name="LOG_HOME" value="d:/logback/" />
<property name="appName" value="springboot"></property>
<appender name="cc" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</layout>
</appender>
<appender name="ff" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${appName}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
<MaxHistory>365</MaxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>10MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
</layout>
</appender>
<logger name="com.bjpowernode.controller" level="debug" />
<logger name="org.springframework" level="debug" additivity="false"></logger>
<root level="info">
<appender-ref ref="cc" />
<appender-ref ref="ff" />
</root>
</configuration>
工具
自定义配置提示
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
热部署
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
lombok
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
@Accessors(chain = true)
Student s3 = new Student()
.setId(30)
.setName("王五")
.setAddress("深圳")
.setScore(82.6);
System.out.println(s3);
注解式日志
@Slf4j
public class LogController {
@GetMapping("/getLog")
public String getLog(){
log.error("error级别的日志");
log.warn("warn级别的日志");
log.info("info级别的日志");
log.debug("debug级别的日志");
log.trace("trace级别的日志");
log.info("无需重启自动生效...");
return "正在记录日志";
}
}
处理静态资源
配置静态资源路径
-
默认位置
-
配置自定义位置 -
配置静态资源访问路径 spring:
web:
resources:
static-locations: classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/,classpath:/my/,file:${custom.upload}
mvc:
static-path-pattern: /static/**
custom:
upload: E:\文件\图片\壁纸
使用静态资源jar包
-
导入bootstrap和jqury依赖
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.6.0</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.4.1</version>
</dependency>
-
使用demo <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/webjars/bootstrap/3.4.1/css/bootstrap.min.css">
</head>
<body>
<div style="text-align: center">
<h1>首页</h1>
<div>
<span id="hello">你好</span>
</div>
<div>
<button type="button" class="btn btn-primary">按钮</button>
</div>
<div>
<img src="/static/bbb.jpg" alt="" style="width: 300px; height: 200px">
</div>
<script type="text/javascript" src="/webjars/jquery/3.6.0/jquery.min.js"></script>
<script type="text/javascript">
$(function (){
var str = $('#hello').html();
alert(str);
$('#hello').append('springboot');
})
</script>
</div>
</body>
</html>
使用模板引擎 Thymeleaf
配置Thymeleaf
动态属性获取数据
-
取值
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
......
<p th:text="${msg}"></p>
<p th:text="${message}"></p>
<p th:utext="${message}"></p>
<p>[[${msg}]]</p>
<form action="/emp/edit" th:action="@{/emp/edit}" method="post">
<div class="form-group">
<label>员工编号</label>
<input type="text" name="id" class="form-control" th:value="${emp.id}">
</div>
<div class="form-group">
<label>员工姓名</label>
<input type="text" name="ename" class="form-control" th:value="*{ename}">
</div>
<div class="form-group">
<label>入职日期</label>
<input type="date" name="hiredate" class="form-control" th:value="${#dates.format(emp.hiredate, 'yyyy-MM-dd')}">
</div>
<div class="form-group">
<label>员工性别</label>
<select name="gender" class="form-control">
<option value=""></option>
<option value="1" th:selected="${emp.gender=='1'}">男性</option>
<option value="2" th:selected="${emp.gender=='2'}">女性</option>
</select>
</div>
<div class="form-group">
<button type="button" class="btn btn-primary">提交</button>
</div>
</form>
-
循环 <tr th:each="emp : ${empList}">
<td>[[${emp.id}]]</td>
<td th:text="${emp.ename}"></td>
</tr>
-
判断 <td>
<span th:if="${emp.gender=='1'}">男性</span>
<span th:if="${emp.gender=='2'}">女性</span>
</td>
<td th:switch="${emp.gender}">
<span th:case="'1'">帅哥</span>
<span th:case="'2'">靓女</span>
</td>
-
日期格式化
@DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date hiredate;
<td th:text="${#dates.format(emp.hiredate, 'yyyy-MM-dd')}"></td>
-
自动根路径 @{...}
server:
servlet:
context-path: /boot
<p><a href="/emp/list" th:href="@{/emp/list}">员工列表</a></p>
-
路径传参 <td>
<a href="/emp/get/1" th:href="@{'/emp/get/' + ${emp.id}}" class="btn btn-warning btn-xs">编辑</a> 
<a href="#" th:href="@{/emp/remove(id=${emp.id},ename=${emp.ename},job=${emp.job})}" class="btn btn-danger btn-xs">删除</a>
</td>
<form th:action="@{/auth/login}" method="post" style="width: 350px;margin: 10px auto;">
<div style="color: red;">[[${message}]]</div>
<div class="form-group">
<label>用户名</label>
<input type="text" name="username" class="form-control">
</div>
<div class="form-group">
<label>密码</label>
<input type="password" name="password" class="form-control">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">登录</button>
</div>
</form>
SpringMVC配置
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/page/login").setViewName("login");
registry.addViewController("/").setViewName("login");
registry.addViewController("/page/index").setViewName("index");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry
.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/static/**", "/webjars/**", "/auth/login", "/page/login", "/");
}
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new PointConverter());
}
@Override
public void addCorsMappings(CorsRegistry registry) {
}
}
拦截器
public class LoginInterceptor 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("message", "没有登录");
request.getRequestDispatcher("/page/login").forward(request, response);
return false;
}
return true;
}
}
类型转换器
public class PointConverter implements Converter<String, Point> {
@Override
public Point convert(String source) {
String[] ss = source.split(",");
Point point = new Point(ss[0], ss[1]);
return point;
}
}
<p><a th:href="@{/getPoint(point='15,58')}">类型转换器案例</a></p>
web中的三大组件
-
servlet、filter、listener -
默认不支持,需要在配置类中配置bean -
配置三大组件 @Configuration
public class ServletConfig {
@Bean
public ServletRegistrationBean servletRegistrationBean(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
servletRegistrationBean.setServlet(new DemoServlet());
servletRegistrationBean.addUrlMappings("/demo");
servletRegistrationBean.addInitParameter("msg", "hello");
return servletRegistrationBean;
}
@Bean
public FilterRegistrationBean filterRegistrationBean(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new DemoFilter());
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean servletListenerRegistrationBean(){
ServletListenerRegistrationBean servletListenerRegistrationBean = new ServletListenerRegistrationBean();
servletListenerRegistrationBean.setListener(new DemoListener());
return servletListenerRegistrationBean;
}
}
DemoFilter.java @WebFilter("/*")
public class DemoFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("DemoFilter执行了.........");
filterChain.doFilter(servletRequest, servletResponse);
}
}
DemoListener.java @WebListener
public class DemoListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("DemoListener执行了.....");
}
}
DemoServlet.java @WebServlet("/demo")
public class DemoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("DemoServlet.........." + msg);
resp.getWriter().write("ok");
}
private String msg;
@Override
public void init(ServletConfig config) throws ServletException {
msg = config.getInitParameter("msg");
}
}
全局异常处理器
-
public class CustomException extends RuntimeException{
}
-
@RestControllerAdvice
public class GlobalExceptionHander {
@ExceptionHandler(CustomException.class)
public Map<String, Object> customExceptionHandle(CustomException e){
Map<String, Object> map = new HashMap<>();
map.put("code", -2);
map.put("message", "自定义异常发生");
return map;
}
@ExceptionHandler(Exception.class)
public Map<String, Object> exceptionHandle(Exception e){
Map<String, Object> map = new HashMap<>();
map.put("code", -1);
map.put("message", "其他异常发生");
return map;
}
}
全局日期格式化
-
在SpringMVC使用@DateTimeFormat和@JsonFormat @DateTimeFormat(pattern = "yyyy-MM-dd")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date hiredate;
-
application.yml
spring:
mvc:
format:
date: yyyy-MM-dd HH:mm:ss
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
配置文件上传
spring:
servlet:
multipart:
max-file-size: 1MB
max-request-size: 10MB
前后端分离
设置全局跨域处理
-
WebConfig.java配置文件
@Override
public void addCorsMappings(CorsRegistry registry) {
registry
.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("*")
.allowCredentials(true)
.maxAge(3600);
}
-
后端资源 @RestController
public class UserController {
@GetMapping("/user/list")
public List<User> list(){
User user1 = new User(1, "zhangsan", "123");
User user2 = new User(2, "lisi", "123");
User user3 = new User(3, "wangwu", "123");
User user4 = new User(4, "zhaoliu", "123");
return Arrays.asList(user1,user2,user3,user4);
}
}
-
前端请求(另一个项目) $.ajax('http://localhost:8080/boot/user/list',{
type:'get',
success:function (res) {
var str='';
$.each(res,function () {
str+='<tr>';
str+='<td>'+this.id+'</td>';
str+='<td>'+this.username+'</td>';
str+='<td>'+this.password+'</td>';
str+='</tr>';
});
$('#tab').html(str);
}
});
外部Tomcat
-
外部Tomcat支持tomcat jsp,内部Tomcat不支持tomcat jsp -
新建项目的时候与SpringBoot相似,唯一不同是打包方式改为war -
自己配置TomCat -
将静态资源文件放到 webapp/WEB-IF/ 下面 -
自动生成ServletInitializer.java文件
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SpringBoot05JspApplication.class);
}
}
-
可以使用 jsp 文件 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>Title</title>
</head>
<body>
<div style="text-align: center">
<h1>首页</h1>
<p><a href="/hello">测试</a></p>
</div>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<title>成功</title>
</head>
<body>
<div style="text-align: center">
<h1>成功</h1>
<p>${message}</p>
</div>
</body>
</html>
-
Controller @Controller
public class HelloController {
@GetMapping("/hello")
public String hello(HttpServletRequest request){
System.out.println("HelloController中的hello方法执行了....");
request.setAttribute("message", "hello jsp");
return "success";
}
}
-
application.yml
spring:
mvc:
view:
prefix: /WEB-INF/pages/
suffix: .jsp
后端数据校验
数据校验
-
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class Student {
@NotBlank(message = "姓名不能为空")
@Size(message = "姓名长度为4~10个字符", min = 4, max = 10)
private String name;
@NotNull(message = "年龄不能为空")
@Range(message = "年龄范围为0~100岁", min = 0, max = 100)
private Integer age;
@NotBlank(message = "邮箱不能为空")
@Email(message = "邮箱格式不合法")
private String email;
}
-
开启数据校验 @RestController
public class ValidationController {
@PostMapping("/save")
public String save(@Validated Student student, BindingResult bindingResult){
if(bindingResult.hasErrors()){
List<ObjectError> allErrors = bindingResult.getAllErrors();
for (ObjectError error : allErrors) {
System.out.println(error.getDefaultMessage());
}
}else{
System.out.println(student);
}
return "ok";
}
}
配置文件校验
-
application.yml
user:
username: zhangsan
age: 20
email: aa@aa.aa
-
配置类 @SpringBootApplication
@EnableConfigurationProperties(UserProperties.class)
public class Springboot06ValidationApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot06ValidationApplication.class, args);
}
}
@Data
@ConfigurationProperties(prefix = "user")
@Validated
public class UserProperties {
@NotBlank(message = "用户名不能为空")
@Size(message = "用户名长度为6~16个字符", min = 6, max = 16)
private String username;
@NotNull(message = "年龄不能为空")
@Range(message = "年龄范围为0~100岁", min = 0, max = 100)
private Integer age;
@NotBlank(message = "邮箱不能为空")
@Email(message = "邮箱格式不合法")
private String email;
}
正则表达式
-
可以参考JDK手册:java.util.regex / Pattern -
后端使用正则表达式 public class ParttenTests {
@Test
public void run(){
String str = "zhang#123";
System.out.println(str.matches("[abc]"));
System.out.println(str.matches("[^abc]"));
System.out.println(str.matches("[a-zA-Z]"));
System.out.println(str.matches("[0-9]"));
System.out.println(str.matches("[a-zA-Z0-9]"));
System.out.println(str.matches("\\S"));
System.out.println(str.matches("\\w{5,10}"));
System.out.println(str.matches(".{5,10}"));
System.out.println(str.matches(".*"));
System.out.println("14345678901".matches("^1[3|5|6|7|8|9]\\d{9}$"));
boolean result = Pattern.matches("^[0-9]+$", "123");
System.out.println(result);
Pattern pattern = Pattern.compile("^[0-9]+$");
Matcher matcher = pattern.matcher("123a");
System.out.println(matcher.matches());
}
}
-
前端使用正则表达式 <script type="text/javascript">
var regex = /^[0-9]+$/;
var result = regex.test('123');
alert(result);
</script>
-
使用注解
private String email;
aop
-
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
-
Controller @RestController
public class AopController {
@GetMapping("/list")
public String list(){
System.out.println("AopController中的list方法....");
return "ok";
}
}
-
AopAspect.java
@Component
@Aspect
public class AopAspect {
public static final String POINT_CUT = "execution(* com.bjpowernode.controller.*.*(..))";
@Pointcut("execution(* com.bjpowernode.controller.*.*(..))")
public void exp(){}
@Before("execution(* com.bjpowernode.controller.*.*(..))")
public void before(){
System.out.println("切面的前置通知...");
}
@After(POINT_CUT)
public void after(){
System.out.println("切面的后置通知...");
}
@AfterReturning(value = "exp()", returning = "result")
public void returning(Object result){
System.out.println("切面的返回通知..." + result);
}
}
连接数据库
使用jdbc
-
创建项目选择 jdbc api和Mysql Dirver 依赖 -
application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/student
username: root
password: 111111
type: com.alibaba.druid.pool.DruidDataSource
initialSize: 5
minIdle: 10
maxActive: 50
maxWait: 30000
-
entity层 略 -
dao public class DeptDaoImpl implements DeptDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public int insert(Dept dept) {
String sql="insert into dept(dname,loc) values(?,?)";
return jdbcTemplate.update(sql,dept.getDname(),dept.getLoc());
}
}
-
测试 @SpringBootTest
class Springboot08JdbcApplicationTests {
@Autowired
private DataSource dataSource;
@Test
void contextLoads() {
System.out.println("数据源:"+dataSource);
}
@Test
void testJdbc() throws SQLException {
Connection connection = dataSource.getConnection();
String sql="select deptno,dname,loc from dept where deptno=?";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,60);
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
int deptno = resultSet.getInt("deptno");
String dname = resultSet.getString("dname");
String loc = resultSet.getString("loc");
System.out.println("编号="+deptno+" 名字="+dname+" 地址="+loc);
}
resultSet.close();
preparedStatement.close();
connection.close();
}
}
使用数据库连接池Druid
自定义配置类
-
引入依赖,版本号不能省略
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
-
配置文件按application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/student
username: root
password: 111111
type: com.alibaba.druid.pool.DruidDataSource
initialSize: 5
minIdle: 10
maxActive: 50
maxWait: 30000
filters: stat,wall,slf4j
-
自定义的配置类
@Configuration
public class DruidConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource dataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
return druidDataSource;
}
@Bean
public ServletRegistrationBean servletRegistrationBean(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
servletRegistrationBean.setServlet(new StatViewServlet());
servletRegistrationBean.addUrlMappings("/druid/*");
servletRegistrationBean.addInitParameter("loginUsername","admin");
servletRegistrationBean.addInitParameter("loginPassword", "123");
return servletRegistrationBean;
}
@Bean
public FilterRegistrationBean filterRegistrationBean(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.addInitParameter("exclusions", "/druid/*,*.js,*.css,*.jpg,*.png");
return filterRegistrationBean;
}
}
自带配置类
-
引入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
-
配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/student
username: root
password: 111111
initial-size: 6
min-idle: 7
max-active: 15
max-wait: 20000
filter: stat,wall,slf4j
stat-view-servlet:
enabled: true
url-pattern: /druid/*
login-password: 111
login-username: root
web-stat-filter:
enabled: true
url-pattern: /*
exclusions: "/druid/*,*.js,*.css,*.jpg,*.png"
JdbcTemplate工具
-
封装了jdbc的工具 -
DeptDaoImpl.java @Repository
public class DeptDaoImpl implements DeptDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public int insert(Dept dept) {
String sql="insert into dept(dname,loc) values(?,?)";
return jdbcTemplate.update(sql,dept.getDname(),dept.getLoc());
}
@Override
public List<Dept> select() {
String sql = "select deptno, dname, loc from dept order by deptno desc";
RowMapper<Dept> rowMapper = new BeanPropertyRowMapper<>(Dept.class);
List<Dept> list = jdbcTemplate.query(sql, rowMapper);
return list;
}
@Override
public Dept selectById(Integer deptno) {
String sql = "select deptno, dname, loc from dept where deptno=?";
RowMapper<Dept> rowMapper = new BeanPropertyRowMapper<>(Dept.class);
Dept dept = jdbcTemplate.queryForObject(sql, rowMapper, deptno);
return dept;
}
}
-
测试类 @SpringBootTest
class Springboot08JdbcApplicationTests {
@Autowired
private DataSource dataSource;
@Test
void contextLoads() {
System.out.println("数据源:"+dataSource);
if (dataSource instanceof DruidDataSource){
DruidDataSource druidDataSource=(DruidDataSource) dataSource;
System.out.println(druidDataSource.getInitialSize());
System.out.println(druidDataSource.getMinIdle());
System.out.println(druidDataSource.getMaxActive());
System.out.println(druidDataSource.getMaxWait());
}
}
@Autowired
DeptDao deptDao;
@Test
void testInsert(){
Dept dept = new Dept();
dept.setDname("采购部");
dept.setLoc("深圳");
int result = deptDao.insert(dept);
System.out.println(result);
}
@Test
void testSelect(){
List<Dept> list = deptDao.select();
for (Dept dept : list) {
System.out.println(dept);
}
}
@Test
void testSelectById(){
Dept dept = deptDao.selectById(48);
System.out.println(dept);
}
}
整合MyBatis
-
创建项目时,加上MyBatisFramwork依赖 <dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
-
数据库连接池依赖和分页插件
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.2</version>
</dependency>
-
配置文件
spring:
jackson:
date-format: yyyy-MM-dd
time-zone: GMT+8
mvc:
format:
date: yyyy-MM-dd
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/bjpowernode
username: root
password: root
initial-size: 6
min-idle: 7
max-active: 15
max-wait: 20000
filter: stat,wall,slf4j
stat-view-servlet:
enabled: true
url-pattern: /druid/*
login-password: 111
login-username: root
web-stat-filter:
enabled: true
url-pattern: /*
exclusions: "/druid/*,*.js,*.css,*.jpg,*.png"
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.bjpowernode.entity
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
pagehelper:
reasonable: true
-
@SpringBootApplication
@MapperScans({
@MapperScan(basePackages = "com.bjpowernode.dao"),
@MapperScan(basePackages = "com.bjpowernode.dao2")
})
@MapperScan(basePackages = "com.bjpowernode.dao")
public class Springboot09MybatisApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot09MybatisApplication.class, args);
}
}
-
entity @Data
public class Emp {
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Double sal;
private Double comm;
private Integer deptno;
}
-
dao
@Mapper
public interface EmpDao {
List<Emp> select();
Emp selectById(Integer id);
int insert(Emp entity);
int update(Emp entity);
int delete(Integer id);
}
-
mapper <?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.bjpowernode.dao.EmpDao">
<select id="select" resultType="emp">
select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp order by empno asc
</select>
<select id="selectById" parameterType="int" resultType="Emp">
select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp where empno=#{empno}
</select>
<insert id="insert" parameterType="com.bjpowernode.entity.Emp">
insert into emp(ename,job,mgr,hiredate,sal,comm,deptno)
values(#{ename},#{job},#{mgr},#{hiredate},#{sal},#{comm},#{deptno})
</insert>
<update id="update" parameterType="com.bjpowernode.entity.Emp">
update emp set ename=#{ename},job=#{job},mgr=#{mgr},hiredate=#{hiredate},sal=#{sal},comm=#{comm},deptno=#{deptno}
where empno=#{empno}
</update>
<delete id="delete" parameterType="int">
delete from emp where empno=#{empno}
</delete>
</mapper>
-
service public interface EmpService {
Map<String, Object> page(Integer pageNumber, Integer pageSize);
Emp get(Integer id);
boolean save(Emp entity);
boolean update(Emp entity);
boolean remove(Integer id);
}
@Service
public class EmpServiceImpl implements EmpService {
@Autowired
private EmpDao empDao;
@Override
public Map<String, Object> page(Integer pageNumber, Integer pageSize) {
PageHelper.startPage(pageNumber, pageSize);
PageInfo<Emp> pageInfo = new PageInfo<>(empDao.select());
Map<String, Object> pageMap = new HashMap<>();
pageMap.put("list", pageInfo.getList());
pageMap.put("total", pageInfo.getTotal());
return pageMap;
}
@Override
public Emp get(Integer id) {
return empDao.selectById(id);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean save(Emp entity) {
return empDao.insert(entity) > 0;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean update(Emp entity) {
return empDao.update(entity) > 0;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean remove(Integer id) {
return empDao.delete(id) > 0;
}
}
-
Controller @RestController
@RequestMapping("/emp")
public class EmpController {
@Autowired
private EmpService empService;
@GetMapping("/page")
public Map<String, Object> page(Integer pageNumber, Integer pageSize){
Map<String, Object> pageMap = empService.page(pageNumber, pageSize);
Map<String, Object> result = new HashMap<>();
result.put("code", 200);
result.put("message", "ok");
result.put("data", pageMap);
return result;
}
@GetMapping("/get/{id}")
public Map<String, Object> get(@PathVariable("id") Integer id){
Map<String, Object> result = new HashMap<>();
result.put("code", 200);
result.put("message", "ok");
result.put("data", empService.get(id));
return result;
}
@PostMapping("/save")
public Map<String, Object> save(@RequestBody Emp emp){
Map<String, Object> result = new HashMap<>();
result.put("code", 200);
result.put("message", "ok");
result.put("data", empService.save(emp));
return result;
}
@PutMapping("/edit")
public Map<String, Object> edit(@RequestBody Emp emp){
Map<String, Object> result = new HashMap<>();
result.put("code", 200);
result.put("message", "ok");
result.put("data", empService.update(emp));
return result;
}
@DeleteMapping("/remove/{id}")
public Map<String, Object> remove(@PathVariable("id") Integer id){
Map<String, Object> result = new HashMap<>();
result.put("code", 200);
result.put("message", "ok");
result.put("data", empService.remove(id));
return result;
}
}
Api接口文档 swagger
-
引入依赖
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
-
配置文件
swagger3:
base-package: com.dx.controller
name: xxx
url: https://gitee.com/
email: 1233453534@qq.com
version: 1.0
group-name: dx
title: "标题 "
description: "描述信息"
terms-of-service-url: https://gitee.com/
license: cxs
license-url: https://gitee.com/
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
mvc:
format:
date: yyyy-MM-dd HH:mm:ss
pathmatch:
matching-strategy: ant_path_matcher
-
读取配置的类 @Data
@ConfigurationProperties(prefix = "swagger3")
public class SwaggerProperties {
private String basePackage;
private String name;
private String url;
private String email;
private String version;
private String groupName;
private String title;
private String description;
private String termsOfServiceUrl;
private String license;
private String licenseUrl;
}
-
注入配置类,配置swagger @Configuration
@EnableConfigurationProperties(SwaggerProperties.class)
public class SwaggerConfig {
@Autowired
private SwaggerProperties swaggerProperties;
public ApiInfo getApiInfo(){
Contact contact = new Contact(swaggerProperties.getName(), swaggerProperties.getUrl(), swaggerProperties.getEmail());
return new ApiInfoBuilder()
.contact(contact)
.title(swaggerProperties.getTitle())
.description(swaggerProperties.getDescription())
.version(swaggerProperties.getVersion())
.license(swaggerProperties.getLicense())
.licenseUrl(swaggerProperties.getLicenseUrl())
.termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
.build();
}
@Bean
public Docket docket(){
return new Docket(DocumentationType.OAS_30)
.apiInfo(getApiInfo())
.select()
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build();
}
}
-
实体 @Data
@ApiModel("学生实体")
public class Student {
@ApiModelProperty("学生编号")
private Integer id;
@ApiModelProperty("学生姓名")
private String name;
@ApiModelProperty("学生住址")
private String address;
@ApiModelProperty("出生日期")
private Date birthday;
}
-
Controller
-
配置对类的描述注解 -
配置对方法的描述的注解 -
对参数的注解 @RestController
@RequestMapping("/student")
public class StudentController {
@ApiOperation("分页+条件查询 学生信息")
@ApiImplicitParams({
@ApiImplicitParam(name = "pageNumber", value = "当前页码", required = false, dataType = "Integer",defaultValue = "1", paramType = "query"),
@ApiImplicitParam(name = "pageSize", value = "每页条数", required = false, dataType = "Integer",defaultValue = "10", paramType = "query")
})
@ApiResponses({
@ApiResponse(code = 0, message = "成功"),
@ApiResponse(code = -1, message = "失败")
})
@GetMapping("/page")
public Result page(@RequestParam(value = "pageNumber",defaultValue = "1") Integer pagerNumber,
@RequestParam(value = "pageSize",defaultValue = "5") Integer pageSize,
Student student) {
System.out.println(pagerNumber);
System.out.println(pageSize);
System.out.println(student);
return Result.success();
}
@GetMapping("/get/{id}")
@ApiOperation("根据ID获取学生信息")
@ApiImplicitParam(name="id",value = "学生编号",required = true, dataType="Integer", paramType = "path")
public Result get(@PathVariable("id") Integer id) {
System.out.println(id);
return Result.success();
}
@PutMapping("/edit")
@ApiOperation("编辑学生信息")
public Result edit(@RequestBody Student student){
System.out.println(student);
return Result.success();
}
@DeleteMapping("/remove/{id}")
@ApiOperation("根据编号删除学生信息")
@ApiImplicitParam(name = "id", value = "学生编号", required = true, dataType = "Integer", paramType = "path")
public Result remove(@PathVariable("id") Integer id){
System.out.println(id);
return Result.success();
}
}
-
查看swagger页面
其他功能
spring boot 异步
-
异步调用需要配置注解@Async -
启动类 开启异步调用
@EnableAsync
-
案例:统计耗时 @Service
public class AsyncService {
@Async
public void task1(){
try {
long start = System.currentTimeMillis();
Thread.sleep(1000);
long end = System.currentTimeMillis();
System.out.println("task1耗时:" + (end - start) + "毫秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Async
public void task2(){
try {
long start = System.currentTimeMillis();
Thread.sleep(2000);
long end = System.currentTimeMillis();
System.out.println("task2耗时:" + (end - start) + "毫秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Async
public void task3(){
try {
long start = System.currentTimeMillis();
Thread.sleep(3000);
long end = System.currentTimeMillis();
System.out.println("task3耗时:" + (end - start) + "毫秒");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@RestController
public class AsyncController {
@Autowired
private AsyncService asyncService;
@GetMapping("/doAsync")
public Map<String, Object> doAsync(){
long start = System.currentTimeMillis();
asyncService.task1();
asyncService.task2();
asyncService.task3();
Map<String, Object> map = new HashMap<>();
long end = System.currentTimeMillis();
map.put("code", 200);
map.put("message", "调用方法成功,总耗时为" + (end-start) + "毫秒");
return map;
}
}
定时任务
邮件
-
io中的 java mail … 依赖 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
-
开启邮箱pop3的服务,写配置文件 spring:
mail:
host: smtp.qq.com
password: xxxxxceoibdaaaaa
username: 11118422@qq.com
default-encoding: UTF-8
-
发送简单的内容 @Autowired
private JavaMailSender javaMailSender;
@Test
void testSend() {
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
simpleMailMessage.setFrom("11112342@qq.com");
simpleMailMessage.setTo("22212342@qq.com");
simpleMailMessage.setSubject("这是一个测试邮件20220812");
simpleMailMessage.setText("测试内容2022-08-12");
javaMailSender.send(simpleMailMessage);
}
-
发送邮件工具类
@Test
void testSend2() throws MessagingException {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage,true,"utf-8");
mimeMessageHelper.setFrom("28718422@qq.com");
mimeMessageHelper.setTo("28718422@qq.com");
mimeMessage.setSubject("这是一个携带了图片和附件的邮件20220812");
StringBuilder sb = new StringBuilder();
sb.append("<html> <body> <h1 style='color:red'>springboot 测试邮件发送复杂格式o</h1>");
sb.append("<p style='color:blue;font-size:16px'>哈哈哈</p>");
sb.append("<p style='text-align:center'>居中</p>");
sb.append("<img src='cid:picture'/> </body></html>");
mimeMessageHelper.setText(sb.toString(), true);
mimeMessageHelper.addInline("picture",new File("C:\\Users\\NINGMEI\\Desktop\\aaa\\ddd.jpg"));
mimeMessageHelper.addAttachment("SpringBoot.doc",new File("D:\\course\\05-SpringBoot\\springboot\\document\\SpringBoot.doc"));
javaMailSender.send(mimeMessage);
}
|