文章目录
- 常用模板
- 1.java的HelloWord
- 2.controller测试模板
- 2.1.返回json
- 2.2.返回页面
- 3.oracle分页模板
- 4.servlet模板
- 5.springboot.pom依赖模板(待补充)
- 6.mybatis的mapper.xml模板
- 7.vue单页面快速整合axios模板
- 8.logback日志模板
- 9.js的单击事件alert的Helloworld
- 10.jQuery的单击事件alert的Helloworld
- 11.springboot的yml模板(ssm+redis)
- 12.Thmeleaf模板(循环遍历)
- 13.jsp模板(循环遍历)
- 14.bootstrap快速开始模板
- 14.1.使用cdn的方式引入bootstrap
- 14.2.使用本地文件方式引入bootstrap
- 15.ssm种dao层测试模板
- 16.springboot项目中全局跨域配置类
- 17.springboot全局时间格式处理配置类
- 18.springboot使用redis整合session共享的配置类
- 19.springboot整合swagger配置类
- 20.springboot中拦截器使用模板
- 21.文件上传
- 单文件上传
- 多文件上传
- ajax单文件上传
- 22.jQuery的ajax模板
- 23.VO类的模板
- `Msg`(借见的vo类)
- `R`(人人开源项目的vo类)
- 24.Mybatis-plus逆向工程的模板
- 25.AOP切面模板
- 25.mybatis-plus方法使用示例
- 26.mybatis特殊字符转义
- 27.文件下载模板
- 28.springboot排除拦截静态资源模板
- 一般拦截器模板
- 普通的模板,静态资源设置
- 自己总结的一套拦截路径的模板
- 参考网上案例模板
- 29.springboot打war包模板
- 30.axios+vue发送异步请求模板
- 31.springfox 3.0.0的swagger
- 32.本地测试跨域配置是否生效
- 33.mybatis懒加载
- springboot整合mybatis懒加载
- mybatis-plus配置
- mybaits配置
- ssm项目配置懒加载
- 34.html常用表单标签使用模板
- 36.springboot整合mybatis多数据源
- 基于路径实现多数据源
- 1.准备数据库表
- 2.搭建项目
- 3.项目整体目录
- 4.测试
- 37.springboot整合mybatis-plus多数据源配置
- 1.@DS注解的介绍和使用
- 2.测试
- 不指定master数据源进行测试
- 38.原生ajax模板整理
- 1.ajax过程
- 2.准备测试的接口
- 3.ajax测试模板
- 4.测试
- 39.springboot整合swagger+knife4j
- 准备工作
- 1.整合swagger3.0
- 2.整合knife4j
- 使用
- 1.访问网址
- 40.springboot整合mybatis-plus逆向工程配置
- 简介
- 添加的依赖
- 代码模板
- 踩坑记录
- ClassNotFoundException: com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator
- 41.springmvc四种类型返回值
- 42.springcache+redis 缓存数据
- 43.StringUtils和StrUtil(Hutool)常用操作字符窜方法使用模板
- 44.测试跨域的html页面
- 45.springboot整合knife4j(快速通用版)
- 引入pom.依赖
- swagger配置类
- `knife4j访问网址`
- 说明:
- 46.maven配置阿里云镜像的两种方式
- 配置方式
- 第一种方式(settings.xml文件)
- 第二种方式(pom.xml方式)
- 区别
- 47.Vagrantfile模板
- 48.springboot使用undertow代替tomcat
- nginx 配置 http
1.java的HelloWord
public class Hello {
public static void main(String[] args) {
System.out.println("Hello World 顺便测试中文乱码");
}
}
2.controller测试模板
2.1.返回json
2.2.返回页面
3.oracle分页模板
- sql
SELECT * FROM
(
SELECT A.*, ROWNUM RN
FROM (
SELECT * FROM EMPLOY
) A
WHERE ROWNUM <= 40
)
WHERE RN >= 21
- mapper.xml模板
<select id="findByNameByPageObject"
resultType="com.fcmap.ssm.domain.Demo">
select * from(
SELECT A.*, ROWNUM RN
FROM (
SELECT * FROM DEMO
<where>
<if test="name!=null and name!='' and name!='all'">
and name like '%'||#{name}||'%'
</if>
</where>
) A
WHERE
ROWNUM <![CDATA[ <= ]]>
(#{pageIndex}*#{pageSize})
)
<where>
RN <![CDATA[ >= ]]>
((#{pageIndex}-1)*#{pageSize})+1
</where>
</select>
4.servlet模板
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
*/
public class TestServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//>>处理POST请求参数乱码
request.setCharacterEncoding("utf-8");
//>>处理响应正文乱码
response.setContentType("text/html;charset=utf-8");
//TODO...
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
5.springboot.pom依赖模板(待补充)
<?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 http://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.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hxh</groupId>
<artifactId>basic_project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>basic_project</name>
<description>基础项目框架</description>
<properties>
<java.version>1.8</java.version>
<swagger.version>2.9.2</swagger.version>
<velocity.version>2.1</velocity.version>
<mybatis-plus.version>3.1.2</mybatis-plus.version>
<freemarker.version>2.3.28</freemarker.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--java制造假数据的工具类-->
<dependency>
<groupId>com.github.javafaker</groupId>
<artifactId>javafaker</artifactId>
<version>1.0.2</version>
</dependency>
<!-- springboot测试需要的注解 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 数据库生成模板的核心依赖 -->
<dependency>
<groupId>cn.smallbun.screw</groupId>
<artifactId>screw-core</artifactId>
<version>1.0.3</version>
</dependency>
<!-- 引入hutool工具类-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.4</version>
</dependency>
<!--引入google处理json数据的依赖-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
<!-- aop相关依赖 (@Aspect这个注解需要这个依赖) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 引入pagehlper分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.4</version>
</dependency>
<!--redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- web依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 热部署工具 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<!-- mysql 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- swagger ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<!-- mybatis_plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- 模板引擎 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>${velocity.version}</version>
</dependency>
<!-- 代码生成器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- freemarker 模板引擎 -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>${freemarker.version}</version>
</dependency>
</dependencies>
<build>
<finalName>BasicProject</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<!-- 配置环境 -->
<profiles>
<profile>
<!-- 开发 -->
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<activatedProperties>dev</activatedProperties>
</properties>
</profile>
<profile>
<!-- 测试 -->
<id>test</id>
<properties>
<activatedProperties>test</activatedProperties>
</properties>
</profile>
<profile>
<!-- 准生产 -->
<id>pre</id>
<properties>
<activatedProperties>pre</activatedProperties>
</properties>
</profile>
<profile>
<!-- 生产 -->
<id>prod</id>
<properties>
<activatedProperties>prod</activatedProperties>
</properties>
</profile>
</profiles>
</project>
6.mybatis的mapper.xml模板
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.fct.njjg.mapper.HlwjgJcssqdDao">
<!-- 开启二级缓存 -->
<cache type="org.mybatis.caches.ehcache.LoggingEhcache"/>
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="com.fct.njjg.pojo.entity.HlwjgJcssqd">
<result column="RD" property="rd"/>
<result column="DETAIL_CODE" property="detailCode"/>
<result column="INVENTORY_CODE" property="inventoryCode"/>
<result column="CREATE_DEPARTMENT_ID" property="createDepartmentId"/>
<result column="JHPT_UPDATE_TIME" property="jhptUpdateTime"/>
<result column="MATTER_CODE" property="matterCode"/>
<result column="ORG_CODE" property="orgCode"/>
<result column="ORG_NAME" property="orgName"/>
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
RD, DETAIL_CODE, INVENTORY_CODE, CREATE_DEPARTMENT_ID, JHPT_UPDATE_TIME, MATTER_CODE, ORG_CODE, ORG_NAME
</sql>
</mapper>
7.vue单页面快速整合axios模板
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap 101 Template</title>
<!-- Bootstrap -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
rel="stylesheet">
<script
src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
<!-- 引入外部的css文件 -->
<link rel="stylesheet" type="text/css" href="css/emplist.css">
<!-- 引入vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 引入axios.js -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<!-- 把empList数组里面的数据显示,使用v-for -->
<hr>
<table class="table table-condensed">
<tr v-for="emp in empList">
<td>{{emp.id}}</td>
<td>{{emp.name}}</td>
<td>{{emp.job}} </td>
<td>{{emp.salary}}</td>
</tr>
</table>
<div v-for="emp in empList">
{{emp.id}} =========> {{emp.name}} --->{{emp.job}} ---->{{emp.salary}}
</div>
</div>
<script>
/**
* axios发送ajax请求的步骤
* 1.引入vue.js和axios.js这两个文件
* 2.发送ajax请求
*/
new Vue({
el:'#app',
//固定结构
data:{ //在data定义变量和初始值
//定义变量,值空数组
empList:[]
},
created(){
//页面渲染之前执行
//调用定义的方法
this.getempList()
},
methods:{//编写具体的方法
//创建方法,查询所有用户数据
getempList(){
//使用axios发送ajax请求
//axion.提交方式("请求接口路径").then(箭头函数).catch(箭头函数)
axios.get("http://rap2api.taobao.org/app/mock/261964/findall")
.then(response=>{
//console.log(response);
this.empList = response.data
console.log(this.empList)
})
.catch(error=>{
console.log("axios发送ajax请求失败");
})
}
}
})
</script>
</body>
</html>
8.logback日志模板
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property name="FILE_ERROR_PATTERN"
value="${FILE_LOG_PATTERN:-%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} %file:%line: %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" />
<include
resource="org/springframework/boot/logging/logback/defaults.xml" />
<appender name="CONSOLE"
class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<appender name="FILE_INFO"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--如果只是想要 Info 级别的日志,只是过滤 info 还是会输出 Error 日志,因为 Error 的级别高, 所以我们使用下面的策略,可以避免输出
Error 的日志 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--过滤 Error -->
<level>ERROR</level>
<!--匹配到就禁止 -->
<onMatch>DENY</onMatch>
<!--没有匹配到就允许 -->
<onMismatch>ACCEPT</onMismatch>
</filter>
<!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天的日志改名为今天的日期。即,<File>
的日志都是当天的。 -->
<!--<File>logs/info.spring-boot-demo-logback.log</File> -->
<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy -->
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间 -->
<FileNamePattern>logs/info.created_on_%d{yyyy-MM-dd}.part_%i.log</FileNamePattern>
<!--只保留最近90天的日志 -->
<maxHistory>90</maxHistory>
<!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志 -->
<!--<totalSizeCap>1GB</totalSizeCap> -->
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- maxFileSize:这是活动文件的大小,默认值是10MB,本篇设置为1KB,只是为了演示 -->
<maxFileSize>2MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!--<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> -->
<!--<maxFileSize>1KB</maxFileSize> -->
<!--</triggeringPolicy> -->
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
</appender>
<appender name="FILE_ERROR"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--如果只是想要 Error 级别的日志,那么需要过滤一下,默认是 info 级别的,ThresholdFilter -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>Error</level>
</filter>
<!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天的日志改名为今天的日期。即,<File>
的日志都是当天的。 -->
<!--<File>logs/error.spring-boot-demo-logback.log</File> -->
<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy -->
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间 -->
<FileNamePattern>logs/error.created_on_%d{yyyy-MM-dd}.part_%i.log</FileNamePattern>
<!--只保留最近90天的日志 -->
<maxHistory>90</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- maxFileSize:这是活动文件的大小,默认值是10MB,本篇设置为1KB,只是为了演示 -->
<maxFileSize>2MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>${FILE_ERROR_PATTERN}</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
</appender>
<root level="info">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE_INFO" />
<appender-ref ref="FILE_ERROR" />
</root>
</configuration>
9.js的单击事件alert的Helloworld
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<button id="btn"></button>
<script>
function f1(){
alert("hello world");
}
document.getElementById("btn").onclick=f1
</script>
</body>
</html>
10.jQuery的单击事件alert的Helloworld
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--引入jQuery-->
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>
<button id="btn1">我是一个按钮(测试公用的jQuery库是否引入成功)</button>
<script>
$(function(){
$("#btn1").click(function(){
alert("hello jQuery ");
});
});
</script>
</body>
</html>
11.springboot的yml模板(ssm+redis)
server:
port: 8086
servlet:
context-path: /
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
# driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/yonghedb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false
username: root
password: root
#springboot整合redis的配置模板
redis:
database: 0
host: localhost
port: 6379
password:
#支持另外两种请求方式,就是一共支持四种请求方式
mvc:
hiddenmethod:
filter:
enabled: true
#跳转页面需要配置视图解析器
thymeleaf: #引入mvn配置
prefix: classpath:/templates/pages/ # /默认代表根目录 src/main/webapp
suffix: .html
mode: LEGACYHTML5
#spring整合Mybatis-plus
mybatis:
#定义别名包
type-aliases-package: com.shaoming.entity
#加载mapper映射文件
mapper-locations: classpath:/mappers/*.xml
#开启驼峰映射
configuration:
map-underscore-to-camel-case: true
#添加mybatis的sql日志
logging:
level:
com.shaoming.dao: debug
12.Thmeleaf模板(循环遍历)
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap 101 Template</title>
<!-- Bootstrap -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
rel="stylesheet">
<script
src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
<style type="text/css">
#div2{
text-align: center;
border: 3px solid red;
}
a{
font-size: 25px;
}
</style>
</head>
<body>
<!-- 查询所有员工列表页面 -->
<h1 align="center">员工列表信息</h1>
<!-- 这个表格示显示员工数据的 -->
<div align="center"><a th:href="@{/emp_add}">添加员工信息</a></div>
<div id="div2">
<table class="table table-condensed">
<thead>
<tr>
<td>编号</td>
<td>ID</td>
<td>NAME</td>
<td>JOB</td>
<td>SALARY</td>
<td>OPTENTATION(操作)</td>
</thead>
<tbody>
<tr th:each="emp,varstatus:${emps}">
<td th:text="${varstatus.count}"></td>
<td th:text="${emp.id}"></td>
<td th:text="${emp.name}"></td>
<td th:text="${emp.job}"></td>
<td th:text="${emp.salary}"></td>
<td>
<a th:href="@{/toupdate(id=${emp.id})}">修改</a>
<a th:href="@{/deleteById(id=${emp.id})}">删除</a>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
13.jsp模板(循环遍历)
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<style type="text/css">
/* 这里可以书写css样式 */
table {
border: 2px solid red;
/* 设置表格的边框和单元格的边框合并 */
border-collapse: collapse;
/* 设置当前元素的左右编剧自适应,即设置
当前元素水平方向居中
*/
margin-left: auto;
margin-right: auto;
/* 设置背景颜色 */
background: lightgrey;
}
td, th {
border: 2px solid red;
/* 设置单元格边框和内容之间的距离 */
padding: 5px;
}
h1 {
/* 让当前元素的内容居中显示 */
text-align: center;
}
div {
text-align: center;
}
a {
color: orange;
}
#ad{
color: red;
}
</style>
<title>您好Springboot</title>
</head>
<body>
<div>
<a href="${ pageContext.request.contextPath }/emp/emp_insert">添加</a>
</div>
<hr>
<table>
<thead>
<tr>
<th>编号</th>
<th>id</th>
<th>名字</th>
<th>工作</th>
<th>薪资</th>
<th>操作</th>
</tr>
<c:forEach items="${ emps }" var="emp" varStatus="state">
<tr>
<td>${ state.count }</td>
<td>${ emp.id }</td>
<td>${ emp.getName() }</td>
<td>${ emp.job }</td>
<td>${ emp.salary }</td>
<td align="center">
<a id="ad" href="${ pageContext.request.contextPath }/emp/deletebyid?id=${ emp.id}">删除</a>
|
<a id="au" href="${ pageContext.request.contextPath }/emp/selectbyid?id=${ emp.id }">修改</a>
</td>
</tr>
</c:forEach>
</table>
</body>
</html>
14.bootstrap快速开始模板
14.1.使用cdn的方式引入bootstrap
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap 101 Template</title>
<!-- Bootstrap -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
</head>
<body>
<h1>你好,世界!</h1>
</body>
</html>
14.2.使用本地文件方式引入bootstrap
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap 101 Template</title>
<!-- Bootstrap -->
<link href="./css/bootstrap.min.css" rel="stylesheet">
<script src="./js/bootstrap.min.js"></script>
</head>
<body>
<h1>你好,世界!</h1>
</body>
</html>
说明:
说明:
这种方式是从官网下载bootstrap的js和css
然后放到springboot的static目录下
15.ssm种dao层测试模板
重点说明
首先要在spring配置文件中添加如下配置,否则测试混滚的事务不会生效
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
/**
* 测试dao层
* @author Admin
*
*/
@ContextConfiguration("classpath:/spring-mybatis.xml")
@RunWith(SpringJUnit4ClassRunner.class)
//这里可以声明一个事务管理 每个单元测试都进行事务回滚 无论成功与否
@TransactionConfiguration(defaultRollback = true)
@Transactional
public class DemoDaoTest {
@Autowired
private DemoDao demoDao;
/**
* 测试查询所有
*/
//@Rollback(false) 这个是不会滚,这个是提交
//不设置就是回滚
//设置@Rollback也是回滚
@Test
public void testFindAll() {
List<Demo> demoList = demoDao.findAll();
demoList.forEach(System.out::println);
}
16.springboot项目中全局跨域配置类
说明:
springboot处理跨域请求的方式
1.在Controller类上加注解
@CrossOrigin
2.配置类:如下
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/**
springboot处理跨域请求的注解
* 处理跨域请求
* @author ydb
* @date 2020/10/19 10:04
*/
@Configuration
public class CorsConfig {
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");// 1允许任何域名使用
corsConfiguration.addAllowedHeader("*");// 2允许任何头
corsConfiguration.addAllowedMethod("*"); // 3允许任何方法(post、get等)
return corsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig());
return new CorsFilter(source);
}
}
17.springboot全局时间格式处理配置类
/**
* 全局日期格式化
*/
@JsonComponent
public class DateFormatConfig {
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/**
* 日期格式化
*/
public static class DateJsonSerializer extends JsonSerializer<Date> {
@Override
public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(dateFormat.format(date));
}
}
/**
* 解析日期字符串
*/
public static class DateJsonDeserializer extends JsonDeserializer<Date> {
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
try {
return dateFormat.parse(jsonParser.getText());
} catch (ParseException e) {
throw new RuntimeException(e);
}
}
}
}
18.springboot使用redis整合session共享的配置类
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400*30)
public class SessionConfig {
}
19.springboot整合swagger配置类
@Configuration
@EnableSwagger2 // 标记项目启用 Swagger API 接口文档
public class SwaggerConfiguration {
@Bean
public Docket createRestApi() {
// 创建 Docket 对象
return new Docket(DocumentationType.SWAGGER_2) // 文档类型,使用 Swagger2
.apiInfo(this.apiInfo()) // 设置 API 信息
// 扫描 Controller 包路径,获得 API 接口
.select()
.apis(RequestHandlerSelectors.basePackage("com.fct.controller"))
.paths(PathSelectors.any())
// 构建出 Docket 对象
.build();
}
/**
* 创建 API 信息
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("设置主题")
.description("我是一段描述")
.version("1.0.0") // 版本号
.build();
}
}
20.springboot中拦截器使用模板
拦截器配置模板
package com.shaoming.interceptor;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Auther: shaoming
* @Date: 2020/12/31 14:02
* @Description:
*/
@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("拦截器preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("拦截器postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) throws Exception {
System.out.println("拦截器afterCompletion");
}
}
拦截器注入模板
package com.shaoming.config;
import com.shaoming.interceptor.MyInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @Auther: shaoming
* @Date: 2020/12/31 14:07
* @Description:
* 拦截器配置
*/
@Configuration
public class MyInterceptorConfig implements WebMvcConfigurer {
@Autowired
private MyInterceptor myInterceptor;
/**
* 拦截器注册
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor);
/**
* registry.addInterceptor(new LoginInterceptor())
* // addPathPatterns 用于添加拦截规则
* .addPathPatterns("/**")
* .excludePathPatterns("/swagger-ui.html")
* .excludePathPatterns("/swagger-resources/**")
* .excludePathPatterns("/error")
* .excludePathPatterns("/webjars/**");
* WebMvcConfigurer.super.addInterceptors(registry);
*/
}
}
21.springboot中过滤器使用模板
过滤器配置模板
package com.shaoming.filter;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @Auther: shaoming
* @Date: 2020/12/31 14:04
* @Description: 自定义过滤器
*/
@Component
public class MyFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
System.out.println("filter执行前");
filterChain.doFilter(httpServletRequest,httpServletResponse);
System.out.println("filter执行后");
}
}
过滤器注册使用模板
package com.shaoming.config;
import com.shaoming.filter.MyFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Configuration;
/**
* @Auther: shaoming
* @Date: 2020/12/31 14:09
* @Description:
*/
@Configuration
public class MyFilterConfig {
@Autowired
private MyFilter myFilter;
public FilterRegistrationBean getMyFilter(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(myFilter);
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.setOrder(1);
return filterRegistrationBean;
}
}
21.文件上传
单文件上传
springboot配置文件
spring.servlet.multipart.max-file-size=2MB
spring.servlet.multipart.max-request-size=2MB
file.upload.path=G:/testfile/
# file.upload.path=/Users/didi/ #mac系统的路径
# file.upload.path=/opt/myfile/ #linux系统路径
html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/需要上传的文件地址" method="post" enctype="multipart/form-data">
<input type="file" name="fileupload">
<input type="submit" value="上传">
</form>
</body>
</html>
controller
@Slf4j
@Controller
public class UploadController {
@Value("${file.upload.path}")
private String path;
@GetMapping("/")
public String uploadPage() {
return "upload";
}
@PostMapping("/upload")
@ResponseBody
public String create(@RequestPart MultipartFile file) throws IOException {
String fileName = file.getOriginalFilename();
String filePath = path + fileName;
File dest = new File(filePath);
Files.copy(file.getInputStream(), dest.toPath());
return "Upload file success : " + dest.getAbsolutePath();
}
}
多文件上传
springboot配置文件同上
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>多文件上传页面</title>
</head>
<body>
<h1 style="text-align: center;color: royalblue">测试多文件上传的页面</h1>
<!--
文件上传的要素
1.表单是post请求
2.input的type时file类型
3.表单声明数据类型 enctype="multipart/form-data">
-->
<form action="/uploadfiles" method="post" enctype="multipart/form-data">
文件1:<input type="file" name="files"/>
<br data-tomark-pass>
文件2:<input type="file" name="files"/>
<br data-tomark-pass>
<hr>
<input type="submit" value="提交"/>
</form>
</body>
</html>
controller
package com.shaoming.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import java.nio.file.Files;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
/**
* @Auther: shaoming
* @Date: 2021/1/8 10:53
* @Description:
*/
@Controller
@Api(tags = "测试多文件上传")
public class FilesController {
@Value("${file.upload.path}")
private String path;
@GetMapping("/uploads")//get请求
@ApiOperation(value = "跳转到多文件上传页面", notes = "测试多文件上传", httpMethod = "")
public String toUploadManyFiles(HttpServletRequest request) {
return "uploads";
}
@PostMapping("uploadfiles")//请求方式
@ResponseBody
@ApiOperation(value = "多文件上传", notes = "测试多文件上传", httpMethod = "")//swagger方法注解
public String uploadFiles(@RequestPart MultipartFile[] files) throws IOException {
StringBuffer message = new StringBuffer();
for (MultipartFile file : files) {
String fileName = file.getOriginalFilename();
String filePath = path + fileName;
File dest = new File(filePath);
Files.copy(file.getInputStream(), dest.toPath());
message.append("Upload file success : " + dest.getAbsolutePath()).append("<br>");
}
return message.toString();
}
}
ajax单文件上传
springboot配置文件同上
html
<!DOCTYPE html>
<html lang="en">
<script src="../js/jquery-1.8.3.min.js"></script>
<head>
<meta charset="UTF-8">
<title>静态页面-ajax上传</title>
</head>
<body>
<div id="result"></div>
<input type="file" id="file">
<input type="button" value="上传" onclick="uploadFile()">
<script>
function uploadFile() {
var file = $("#file")[0].files[0];
var formData = new FormData();
formData.append("file",file);
$.ajax({
type:'post',
url:'/upload',
processData:false,
contentType:false,
data:formData,
success:function(msg) {
alert("sb")
$('#result').html(msg)
}
})
}
</script>
</body>
</html>
controller
@PostMapping("/upload")//请求方式
@ResponseBody
@ApiOperation(value = "文件上传", notes = "", httpMethod = "")//swagger方法注解
public String upload(@RequestPart MultipartFile file) throws IOException {
String fileName = file.getOriginalFilename();
String filePath = path + fileName;
File dest = new File(filePath);
Files.copy(file.getInputStream(), dest.toPath());
return "Upload file success : " + dest.getAbsolutePath();
}
/**
* ajax文件上传
*/
@GetMapping("/ajaxupload")//get请求
@ApiOperation(value = "ajax文件上传页面", notes = "", httpMethod = "")
public String ajaxuploadHtml() {
return "ajax";
}
22.jQuery的ajax模板
- ajax通用模板方法
$.ajax({
url : "userList.json",//请求的url
method : "GET",//请求的方式
contentType: "application/json",//请求数据为json格式
data : null,//请求的参数
async : true,//默认为true,表示异步请求
dataType : "text",//返回的数据时json格式的对象,如果是字符窜,简单类型一般就是text类型
success : function(data){
console.log(data);
},//定义成功的回调函数
error : function() {
alert("ajax请求失败");
}//失败的回调函数
});
- get方法
- post方法
- getJson方法
23.VO类的模板
Msg
(借见的vo类)
package com.fct.njjg.model.vo;
import java.util.HashMap;
import java.util.Map;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel("视图返回对象,jsonresult")
public class Msg {
// 状态码 100 成功 200 失败
@ApiModelProperty(value = "响应码")
private int code;
// 提示信息
@ApiModelProperty(value = "提示信息")
private String msg;
// 用户要返回给客户端的数据
@ApiModelProperty(value = "数据信息")
private Map<String, Object> data = new HashMap<String, Object>();
// 当前对象添加用户要返回给客户端的数据
public Msg add(String key, Object value) {
this.getData().put(key, value);
return this;
}
// 执行成功
public static Msg success() {
Msg result = new Msg();
result.setCode(100);
result.setMsg("执行成功!");
return result;
}
// 执行失败
public static Msg fail() {
Msg result = new Msg();
result.setCode(200);
result.setMsg("执行失败!");
return result;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Map<String, Object> getData() {
return data;
}
public void setData(Map<String, Object> data) {
this.data = data;
}
}
R
(人人开源项目的vo类)
package com.ckf.springbootswagger.pojo;
import java.util.HashMap;
import java.util.Map;
/**
* 返回数据
*
* @author Mark sunlightcs@gmail.com
*/
public class R extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
// private Integer code;
// private String msg;
// private Object data;
public R() {
put("code", 0);
}
public static R error() {
return error(500, "未知异常,请联系管理员");
}
public static R error(String msg) {
return error(500, msg);
}
public static R error(int code, String msg) {
R r = new R();
r.put("code", code);
r.put("msg", msg);
return r;
}
public static R ok(String msg) {
R r = new R();
r.put("msg", msg);
return r;
}
public static R ok(Map<String, Object> map) {
R r = new R();
r.putAll(map);
return r;
}
public static R ok() {
return new R();
}
public R put(String key, Object value) {
super.put(key, value);
return this;
}
}
24.Mybatis-plus逆向工程的模板
那日志记录表为例
package com.fct.njjg.pojo.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import java.time.LocalDate;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import java.sql.Clob;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <p>
* 日志记录表
* </p>
*
* @author shaoming
* @since 2020-11-05
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("SYS_INFO_LOG")
@ApiModel(value="SysInfoLog对象", description="日志记录表")
public class SysInfoLog extends Model<SysInfoLog> {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "主键ID")
@TableId(value = "OPER_ID", type = IdType.NONE)
private String operId;
@ApiModelProperty(value = "功能模块")
@TableField("OPER_MODUL")
private String operModul;
@ApiModelProperty(value = "操作类型")
@TableField("OPER_TYPE")
private String operType;
@ApiModelProperty(value = "操作描述")
@TableField("OPER_DESC")
private String operDesc;
@ApiModelProperty(value = "请求参数")
@TableField("OPER_REQU_PARAM")
private Clob operRequParam;
@ApiModelProperty(value = "返回参数")
@TableField("OPER_RESP_PARAM")
private Clob operRespParam;
@ApiModelProperty(value = "操作员ID")
@TableField("OPER_USER_ID")
private String operUserId;
@ApiModelProperty(value = "操作原名称")
@TableField("OPER_USER_NAME")
private String operUserName;
@ApiModelProperty(value = "操作方法")
@TableField("OPER_METHOD")
private String operMethod;
@ApiModelProperty(value = "请求URI")
@TableField("OPER_URI")
private String operUri;
@ApiModelProperty(value = "请求IP")
@TableField("OPER_IP")
private String operIp;
@ApiModelProperty(value = "操作时间")
@TableField("OPER_CREATE_TIME")
private LocalDate operCreateTime;
@ApiModelProperty(value = "操作版本号")
@TableField("OPER_VAR")
private String operVar;
@Override
protected Serializable pkVal() {
return this.operId;
}
}
详细版本实体类模板
package com.example.demo.model.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
* @author shaoming
* @Date: 2021/3/30 01:57
* @Description:实体类(user)
*/
/**
* lombok注解
* @Data 自动生成get/set/toString/hashcode/equals方法
* @AllArgsConstructor 自动为实体类生成全参数的构造器
* @NoArgsConstructor 自动实体类生成无参数构造器
* @Accessors(chain = true) 表示支持来链式加载
* @EqualsAndHashCode(callSuper = false)
* EqualsAndHashCode实则就是在比较两个对象的属性;
* 当@EqualsAndHashCode(callSuper = false)时不会比较其继承的父类的属性可能会导致错误判断;
* 当@EqualsAndHashCode(callSuper = true)时会比较其继承的父类的属性;
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
/**
* @TableName
* 声明实体类对应数据库的表名
*/
@TableName(value = "user")
/**
* @ApiModel
* swagger实体类的注解,一般vlue是 类型对象
* description一般可以设置为表注释
*/
@ApiModel(value = "User对象",description = "对应数据库表名")
public class User extends Model<User> {
/**
* 如果在SpringBoot配置文件配置
* mybatis-plus.global-config.db-config.id-type=auto
* 那么实体类对应主键的属性不需要再声明为主键自增
* 重点说明:
* 如果指定为主键自增,那么需要在创建数据表的时候设置主键自增
* 说明:
* MyBatis-Plus默认的主键策略是:ASSIGN_ID (使用了雪花算法)
* 雪花算法是由Twitter公布的分布式主键生成算法,它能够保证不同表的主键的不重复性,以及相同表的主键的有序性
*/
// @TableId(type = IdType.AUTO)//声明为主键,主键生成方式为主键自增
/**
* @ApiModelProperty
* 这个注解是swagger实体类属性注解,一般可以是数据库字段的注释
* example是示例的数据
*/
@ApiModelProperty(value = "主键ID",example = "1",notes = "主键id的描述信息")
private Long id;
@TableField(value = "name")
@ApiModelProperty(value = "姓名",example = "root",notes = "主键id的描述信息")
private String name;
@TableField(value = "age")
@ApiModelProperty(value = "年龄",example = "18",notes = "用户的年龄")
private Integer age;
@TableField(value = "email")
@ApiModelProperty(value = "邮箱",example = "1025378286@qq.com",notes = "用户的邮箱")
private String email;
}
dao层接口
package com.fct.njjg.mapper;
import com.fct.njjg.pojo.entity.SysInfoLog;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* <p>
* 日志记录表 Mapper 接口
* </p>
*
* @author shaoming
* @since 2020-11-05
*/
public interface SysInfoLogDao extends BaseMapper<SysInfoLog> {
}
service层接口
package com.fct.njjg.service;
import com.fct.njjg.pojo.entity.SysInfoLog;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 日志记录表 服务类
* </p>
*
* @author shaoming
* @since 2020-11-05
*/
public interface SysInfoLogService extends IService<SysInfoLog> {
}
service实现类
package com.fct.njjg.service.impl;
import com.fct.njjg.pojo.entity.SysInfoLog;
import com.fct.njjg.mapper.SysInfoLogDao;
import com.fct.njjg.service.SysInfoLogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 日志记录表 服务实现类
* </p>
*
* @author shaoming
* @since 2020-11-05
*/
@Service
public class SysInfoLogServiceImpl extends ServiceImpl<SysInfoLogDao, SysInfoLog> implements SysInfoLogService {
}
controller
package com.fct.njjg.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 日志记录表 前端控制器
* </p>
*
* @author shaoming
* @since 2020-11-05
*/
@RestController
@RequestMapping("/sysInfoLog")
public class SysInfoLogController {
}
25.AOP切面模板
execution表达式
切入点表达式写法:
参数包括:execution("修饰符 返回值类型 包.类.方法名(参数..) throws异常")
修饰符(举例):一般省略
* 任意
public 公共访问
返回值(举例):
void 无返回值
String 返回值是字符串类型
* 返回值任意
包(举例):
com.xx.user.dao 固定包
com.xx.*.dao com.xx下的任意包中的dao包
com.xx.user.dao.. 包括dao下所有子包中
类(举例):
UserDaoImpl 具体类
User* 以User开头类
*User 以User结尾类
* 任意类
方法(举例):
addUser 具体方法
* 任意方法
*User 以add结尾方法
add* 以add开头方法
参数(无参):
() 无参
(..) 任意参数
(String,int) 1个String和1个int类型的参数
(int) 1个int类型参数
throws,可省略一般不写
切面
package com.shaoming.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import java.lang.reflect.Method;
import java.util.Arrays;
import static java.util.Arrays.*;
/**
* @Auther: shaoming
* @Date: 2020/12/31 15:58
* @Description:
*/
@Order(value = 2)//这个注解表示切面的优先级,数字越小,优先级越大
@Aspect//这个注解表示这个类是一个aop切面
@Component//切面必须交给spring容器管理
public class AopExecution {
@Pointcut("execution(public String com.shaoming.service.MyService.*(String))")
public void point(){
System.out.println("切入点方法的内容不会执行");
}
@Before(value = "point()")
public void doBefore(JoinPoint joinPoint){
System.out.println("前置通知:"+joinPoint);
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
System.out.println("获取请求的类名(去类名:包名+类名)"+joinPoint.getTarget().getClass().getName());
System.out.println("获取方法名的全路径(包名+类名+方法名):"+joinPoint.getTarget().getClass().getName() + "." + signature.getMethod().getName().toString());
System.out.println("获取的方法名称:"+signature.getMethod().getName().toString());
System.out.println("获取参数的名称"+ asList(signature.getParameterNames()));
System.out.println("获取参数的类型"+ asList(signature.getParameterTypes()));
System.out.println("获取方法的返回值的类型:"+signature.getReturnType().toString());
}
@After(value = "point()")
public void doAfter(JoinPoint joinPoint){
System.out.println("后置通知" + joinPoint);
}
@AfterReturning(value = "point()",returning = "res")
public void doAfterReturning(JoinPoint joinPoint,Object res){
System.out.println("返回通知" + joinPoint);
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
System.out.println("====返回通知===获取方法名称"+signature.getMethod().getName());
System.out.println("=====返回通知====获取方法返回值的类型"+signature.getMethod().getReturnType().toString());
System.out.println("=====返回通知中获取方法的返回值:\t" + res);
}
@AfterThrowing(value = "point()",throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint,Exception e){
System.out.println("异常通知:"+joinPoint);
System.out.println("======异常通知===异常信息为:"+e.getMessage());
}
@Around(value = "point()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("=============环绕通知的操作开始获取一些信息================");
System.out.println("环绕通知:" + proceedingJoinPoint);
Object proceed = null;
try {
proceed = proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
System.out.println("=======环绕通知=====获取异常信息为:"+throwable.getMessage());
}
MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
System.out.println("======环绕通知====获取请求的类名(去类名:包名+类名)"+proceedingJoinPoint.getTarget().getClass().getName());
System.out.println("======环绕通知====获取方法名的全路径(包名+类名+方法名):"+proceedingJoinPoint.getTarget().getClass().getName() + "." + signature.getMethod().getName().toString());
System.out.println("======环绕通知====获取的方法名称:"+signature.getMethod().getName().toString());
System.out.println("======环绕通知====获取参数的名称"+ asList(signature.getParameterNames()));
System.out.println("======环绕通知====获取参数的类型"+ asList(signature.getParameterTypes()));
System.out.println("======环绕通知====获取方法的返回值的类型:"+signature.getReturnType().toString());
return proceed;
}
}
25.mybatis-plus方法使用示例
数据库脚本
xxxxxxxxxx 1DROP TABLE IF EXISTS `user`;2CREATE TABLE `user` (3 `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',4 `name` varchar(80) DEFAULT NULL COMMENT '用户名',5 `password` varchar(40) DEFAULT NULL COMMENT '用户密码',6 PRIMARY KEY (`id`)7) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
实体类
@Data
@Accessors(chain=true)
public class User {
private String id;
private String name;
private String password;
}
package com.shaoming;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.shaoming.mapper.UserMapper;
import com.shaoming.model.entity.User;
import com.shaoming.service.IUserService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Calendar;
import java.util.List;
@SpringBootTest
class SpringbootTestDemoApplicationTests {
@Autowired
private IUserService iUserService;
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
}
/**
* 查询所有
*/
@Test
public void testMapper1(){
List<User> users = userMapper.selectList(null);
System.out.println(users);
}
@Test
public void testService1(){
List<User> list = iUserService.list(null);
System.out.println(list);
}
/**
* 按id查询
*/
@Test
public void testMapperSelectById(){
User user = userMapper.selectById(1);
System.out.println(user);
}
@Test
public void testServiceSelectById(){
User user = iUserService.getById(1);
System.out.println(user);
}
/**
* 新增
*/
@Test
public void testMapperInsert(){
for(int i=0 ; i<10 ; i++){
User user = new User();
user.setId(null).setName("root"+i).setPassword("root"+i);
userMapper.insert(user);
}
}
@Test
public void testServiceInsert(){
for(int i=0 ; i<10 ; i++){
User user = new User();
user.setId(null).setName("root"+i).setPassword("root"+i);
iUserService.save(user);
}
}
/**
* 更新
*/
@Test
public void testMapperUpdataById(){
User user = new User();
user.setId("10").setName("root1010").setPassword("root101010");
userMapper.updateById(user);
}
@Test
public void testServiceUpdateById(){
User user = new User();
user.setId("10").setName("root1010").setPassword("root101010");
iUserService.updateById(user);
}
/**
* 根据条件查询集合
* MariaDB [jwt]> select * from user where name = 'root1' and password='root1';
* +----+-------+----------+
* | id | name | password |
* +----+-------+----------+
* | 2 | root1 | root1 |
* | 11 | root1 | root1 |
* +----+-------+----------+
* 2 rows in set (0.000 sec)
*/
@Test
public void testMapperSelectByParam(){
/**
* 报错
* TooManyResultsException
* 因为查询结果不止一条记录
*/
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
// userQueryWrapper.eq("name","root1");//报错,因为root1的记录是两个
userQueryWrapper.eq("name","root2");
System.out.println(userMapper.selectOne(userQueryWrapper));
}
@Test
public void testMapperSelectListByParam(){
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.eq("name","root1");
userQueryWrapper.eq("password","root1");
System.out.println(userMapper.selectList(userQueryWrapper));
}
@Test
public void testServiceSelectByParam(){
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.eq("name","root1");//报错,因为root1的记录是两个
// userQueryWrapper.eq("name","root2");
System.out.println(iUserService.getOne(userQueryWrapper));
}
@Test
public void testServiceSelectListByParam(){
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
userQueryWrapper.eq("name","root1");
userQueryWrapper.eq("password","root1");
System.out.println(iUserService.list(userQueryWrapper));
}
}
26.mybatis特殊字符转义
< | < | 小于号 |
> | > | 大于号 |
& | & | 和 |
’ | ’ | 单引号 |
" | “ | 双引号 |
总结整理
& &
< <
> >
" " //双引号
' ' //单引号
a<=b a <=b 或者 a <![CDATA[<= ]]>b
a>=b a >=b 或者 a <![CDATA[>= ]]>b
a!=b a <![CDATA[ <> ]]>b 或者 a <![CDATA[!= ]]>b
27.文件下载模板
package com.shaoming.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URLEncoder;
/**
* @Auther: shaoming
* @Date: 2021/1/11 13:50
* @Description:
文件下载测试
*/
@Controller
@Slf4j
@Api(tags = "文件下载")
public class FileController {
//@Value注解是引用springboot配置文件的参数
@Value("${local.path}")
private String path;
/**
* 文件下载
*/
@GetMapping("download")
@ApiOperation(value = "springboot项目static目录文件下载", notes = "", httpMethod = "")
public void download(String fileName, HttpServletResponse response) throws Exception
{
//根据文件名去指定目录中查找文件(去springoot默认的static目录下载资源)
String realPath = ResourceUtils.getURL("classpath:").getPath() + "static/files" ;
//获取服务器的路径,如果服务器是windows
// String realPath = "g:/";
//读取文件
File file = new File(realPath, fileName);
//获取文件输入流
FileInputStream is = new FileInputStream(file);
//attachment; 附件下载 inline 在线打开(图片 pdf )
response.setHeader("content-disposition","attachment;fileName="+fileName);
//获取响应输出流
ServletOutputStream os = response.getOutputStream();
//文件拷贝
IOUtils.copy(is,os);
//关流方式(优雅)
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(os);
}
@GetMapping("localdownload")
@ApiOperation(value = "服务器路径文件下载", notes = "", httpMethod = "")
public void localdownload(String fileName, HttpServletResponse response) throws Exception
{
//根据文件名去指定目录中查找文件(去springoot默认的static目录下载资源)
// String realPath = ResourceUtils.getURL("classpath:").getPath() + "static/files" ;
//服务器的路径
String realPath = path;
//读取文件
File file = new File(realPath, fileName);
//获取文件输入流
FileInputStream is = new FileInputStream(file);
//attachment; 附件下载 inline 在线打开(图片 pdf )
/**
* 这种方式设置会有中文乱码
*/
// response.setHeader("content-disposition","attachment;fileName="+fileName);
/**
* 解决文件名中文乱码的问题
*/
response.setHeader("content-disposition","attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8"));
/**
* 设置强制下载不打开
*/
response.setContentType("application/force-download");// 设置强制下载不打开
//获取响应输出流
ServletOutputStream os = response.getOutputStream();
//文件拷贝
IOUtils.copy(is,os);
//关流方式(优雅)
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(os);
}
}
28.springboot排除拦截静态资源模板
一般拦截器模板
package com.lzk.config;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 登录拦截器
*/
public class LoginHandlerInterceptor implements HandlerInterceptor {
/**
* 只需要下面这个(preHandle),配置是否放行配置
* ## 返回值boolean
* -->true:表示放行
* -->false:表示不放行
*
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
/**
* 1.首先:登录成功之后,应该有用户的session
* -->因此如果存在session,说明用户登录了!
* -->如果不存在session,说明用户未登录!
* 2.其次,这个session的值,在LoginController类中设置一个 session参数,
* 校验用户名密码正确后,给这个session设置一个值,然后执行return。
*
*/
Object loginUser = request.getSession().getAttribute("loginUser");
/**
* 2. 然后:判断这个Session值"loginUser"是否存在,
* -->session存在:说明用户已登录了!
* -->session不存在(为空):说明用户未登录!
*/
if (loginUser == null) {
//步骤一:session为空,提示"没有权限,请先登录!"。
request.setAttribute("msg","没有权限,请先登录!");
//步骤二:并将此信息返回首页"index.html"上显示,重定向回去
request.getRequestDispatcher("/index.html").forward(request, response);
//步骤三:未登录,session为空,返回false不放行
return false;
}else{
//登录session不为空,放行-->返回true
return true;
}
/**
* 此时这个拦截器就写好了。
* -->写好后就要配置到bean里面(Spring 的IOC容器中),进行注册!!
* -->到MyMvcConfig类中实现此拦截器"LoginHandlerInterceptor"的注册
*/
}
/**
* 下面的拦截之前/之后(postHandle+afterCompletion),不需要写
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
普通的模板,静态资源设置
设置不拦截静态资源也需要先重写addResourceHandlers添加静态资源路径,然后使用excludePathPatterns方法忽略静态资源路径
package com.yu.aaa;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class InterceptorConfig extends WebMvcConfigurationSupport {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/**").excludePathPatterns("/html/**");
}
// 添加静态资源访问路径
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/static/")
.addResourceLocations("classpath:/templates/");
}
}
自己总结的一套拦截路径的模板
package com.shaoming.config;
import com.shaoming.interceptors.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;
/**
* @Auther: shaoming
* @Date: 2021/1/8 14:11
* @Description: 注册拦截器配置类
*/
@Configuration//表名这是springboot的配置类
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//定义排除swagger访问的路径配置
String[] swaggerExcludes=new String[]{"/swagger-ui.html","/swagger-resources/**","/webjars/**"};
//自定义去除的路径
String[] myExcludes=new String[]{"/hello","/login"};
registry.addInterceptor(new LoginInterceptor())
// addPathPatterns 用于添加拦截规则
.addPathPatterns("/**")
//自己定义的不拦截的规则
.excludePathPatterns(myExcludes)
//去除拦截springboot的静态文件
.excludePathPatterns("/html/*")
.excludePathPatterns("/demo")
.excludePathPatterns("/")
.excludePathPatterns("/error")
//下面是固定格式,如果不配置swagger页面将会访问不了
.excludePathPatterns(swaggerExcludes);
WebMvcConfigurer.super.addInterceptors(registry);
}
//springboot2.x 静态资源在自定义拦截器之后无法访问的解决方案
// @Override
// public void addResourceHandlers(ResourceHandlerRegistry registry) {
// registry.addResourceHandler("/**") //代表以什么样的请求路径访问静态资源
// .addResourceLocations("classpath:/static/")
// .addResourceLocations("classpath:/templates/");
// }
/**
配置url访问到模板中的页面,省略在controller中写彷佛
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/demo").setViewName("demo");
registry.addViewController("/").setViewName("demo");
registry.addViewController("/error").setViewName("error");
}
}
参考网上案例模板
package com.lzk.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 配置扩展MVC-视图解析器
* -->配置接口访问解析跳转
*/
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
//映射:如果controller返回的请求是"main",就给他返回到dashboard,html这个页面。
registry.addViewController("/main.html").setViewName("dashboard");
}
/**
* 1. 自定义的国际化放到Spring IOC容器<bean>中,
* 此时自定义的国际化就生效了!
*
* 2. 此方法就是将自己写的组件配置到Spring容器中,@Bean
*
*/
@Bean
public LocaleResolver localeResolver() {
return new MyLocalResolver();
}
/**
* 1. 下面步骤四:创建一个拦截器相关的类,
* -->实现将刚才写好的拦截器"LoginHandlerInterceptor"注册到Spring的IOC容器中,
* -->实现拦截器类对象的容器注入bean
*
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
//定义排除swagger访问的路径配置
String[] swaggerExcludes=new String[]{"/swagger-ui.html","/swagger-resources/**","/webjars/**"};
//拦截器注入容器,并设置某请求拦截,某些请求不拦截
registry.addInterceptor(new LoginHandlerInterceptor())
//-->.addPathPatterns("/**")设置拦截所有请求"/**"
.addPathPatterns("/**")
/**
* -->排除某一些请求不拦截,
* "index.html":登录页面不拦截,
* "/":首页不拦截
* "user/login":登录请求不拦截
*
* "/css/*":静态资源(css,js..):/css下面的静态资源都放行,不拦截
*/
.excludePathPatterns("/index.html","/","/user/login","/css/*","/js/**","/img/**")
.excludePathPatterns(swaggerExcludes);
}
}
29.springboot打war包模板
1、maven 项目,修改 pom 包
将
<packaging>jar</packaging>
改为
<packaging>war</packaging>
2、打包时排除tomcat.
在这里将 scope 属性设置为 provided,这样在最终形成的 WAR 中不会包含这个 JAR 包,因为 Tomcat 或 Jetty 等服务器在运行时将会提供相关的 API 类。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- 最好加上这个依赖,否者有时候会报错 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
3、注册启动类
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
说明:
return builder.sources(SpringbootTestDemoApplication.class);中的SpringbootTestDemoApplication是启动类的名称,根据自己启动类的名称进行修改
30.axios+vue发送异步请求模板
http://rap2api.taobao.org/app/mock/261964/findall这个是阿里在线接口测试工具平台自己设置的接口
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap 101 Template</title>
<!-- Bootstrap -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
rel="stylesheet">
<script
src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
<!-- 引入外部的css文件 -->
<link rel="stylesheet" type="text/css" href="css/emplist.css">
<!-- 引入vue.js -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 引入axios.js -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<!-- 把empList数组里面的数据显示,使用v-for -->
<hr>
<table class="table table-condensed">
<tr v-for="emp in empList">
<td>{{emp.id}}</td>
<td>{{emp.name}}</td>
<td>{{emp.job}} </td>
<td>{{emp.salary}}</td>
</tr>
</table>
<div v-for="emp in empList">
{{emp.id}} =========> {{emp.name}} --->{{emp.job}} ---->{{emp.salary}}
</div>
</div>
<script>
/**
* axios发送ajax请求的步骤
* 1.引入vue.js和axios.js这两个文件
* 2.发送ajax请求
*/
new Vue({
el:'#app',
//固定结构
data:{ //在data定义变量和初始值
//定义变量,值空数组
empList:[]
},
created(){
//页面渲染之前执行
//调用定义的方法
this.getempList()
},
methods:{//编写具体的方法
//创建方法,查询所有用户数据
getempList(){
//使用axios发送ajax请求
//axion.提交方式("请求接口路径").then(箭头函数).catch(箭头函数)
axios.get("http://rap2api.taobao.org/app/mock/261964/findall")
.then(response=>{
//console.log(response);
this.empList = response.data
console.log(this.empList)
})
.catch(error=>{
console.log("axios发送ajax请求失败");
})
}
}
})
</script>
</body>
</html>
31.springfox 3.0.0的swagger
pom.xml
<!--springfox swagger官方Starter-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
配置类
package com.shaoming.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
/**
* Swagger2API文档的配置
*/
@Configuration
public class Swagger2Config {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.shaoming.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("SwaggerUI演示")
.description("mall-tiny")
.contact(new Contact("macro", null, null))
.version("1.0")
.build();
}
}
访问地址
http://localhost:8080/swagger-ui/
特别注意
新版本和旧版本文档访问路径发生了变化,新版本为:http://localhost:8088/swagger-ui/ ,旧版本为:http://localhost:8088/swagger-ui.html
32.本地测试跨域配置是否生效
参考网址:
随便打开一个网页打开浏览器开发者模式console
var token= "AD3BA267AD984966B3D2179C18FF44F0";
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://127.0.0.1:8080/test');
xhr.setRequestHeader("x-access-token",token);
xhr.send(null);
xhr.onload = function(e) {
var xhr = e.target;
console.log(xhr.responseText);
}
回车 有数据则说明跨域成功,没有token验证的可以去掉token
正常我们测试期间不需要测试token,所以最终模板是:
var xhr = new XMLHttpRequest();
xhr.open('GET', '测试的url地址');
xhr.send(null);
xhr.onload = function(e) {
var xhr = e.target;
console.log(xhr.responseText);
}
33.mybatis懒加载
springboot整合mybatis懒加载
mybatis-plus配置
application.properties
#配置mybatis级联查询懒加载
mybatis-plus.configuration.aggressive-lazy-loading=false
mybatis-plus.configuration.lazy-loading-enabled=true
mybaits配置
application.properties
#配置mybatis级联查询懒加载
mybatis.configuration.aggressive-lazy-loading=false
mybatis.configuration.lazy-loading-enabled=true
ssm项目配置懒加载
在conf文件中配置settings:
<settings>
<!-- 设置驼峰属性 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 配置懒加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 其他配置略 -->
</settings>
34.html常用表单标签使用模板
form.html
<hr><!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style> /* 这里可以书写css样式 */
table{
border:2px solid red;
/* 设置表格的边框和单元格的边框合并 */
border-collapse: collapse;
/* 设置当前元素的左右外边距自适应,即设置
当前元素水平方向居中 */
margin-left:auto;
margin-right:auto;
/* 设置背景颜色 */
background: lightgrey;
}
td,th{
border:2px solid red;
/* 设置单元格的边框和内容之间的距离 */
padding:5px;
}
h1{
/* 让当前元素的内容居中显示 */
text-align: center;
}
</style>
</head>
<body>
<h1>欢迎注册</h1>
<form action="#" method="POST">
<table>
<tr><!-- 用户名 -->
<td>用户名:</td>
<td><!-- 普通文本输入框 -->
<input type="text" name="username"
placeholder="请输入用户名..."/>
</td>
</tr>
<tr><!-- 密码 -->
<td>密码:</td>
<td><!-- 密码输入框 -->
<input type="password" name="pwd"/>
</td>
</tr>
<tr><!-- 性别 -->
<td>性别:</td>
<td><!-- 单选框 -->
<input type="radio" name="gender"
value="male" checked="checked"/>男
<input type="radio" name="gender"
value="female"/>女
</td>
</tr>
<tr><!-- 爱好 -->
<td>爱好:</td>
<td><!-- 复选框/多选框 -->
<input type="checkbox" name="like"
value="basketball" checked="checked"/>篮球
<input type="checkbox" name="like" value="football"/>足球
<input type="checkbox" name="like" value="volleyball"/>排球
</td>
</tr>
<tr><!-- 城市 -->
<td>城市:</td>
<td>
<select name="city">
<option value="bj">北京</option>
<option>上海</option>
<option selected="selected">广州</option>
<option>深圳</option>
</select>
</td>
</tr>
<tr><!-- 自我描述 -->
<td>自我描述:</td>
<td>
<textarea rows="5" cols="30" name="description"
placeholder="请输入描述信息..."></textarea>
</td>
</tr>
<tr><!-- 提交按钮 -->
<td colspan="2" style="text-align:center;">
<input type="submit" value="提交"/>
</td>
</tr>
</table>
</form>
</body>
</html>
效果如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3MfOmNRf-1655909886918)(https://gitee.com/shao_ming314/picture/raw/master/image/image-20210326215518618.png)]
36.springboot整合mybatis多数据源
参考网址
https://mybatis.plus/guide/dynamic-datasource.html#%E6%96%87%E6%A1%A3-documentation
说明
springboot整合mybatis多数据源我搜索了网上的解决方案,大概是两种方式,一个是注解+aop动态切换数据源,一个是基于路径选择
基于路径实现多数据源
1.准备数据库表
建表脚本
CREATE TABLE `demo` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(16) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
下面是两个数据库表中的数据
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i2BNDPl0-1655909886919)(https://gitee.com/shao_ming314/picture/raw/master/image/image-20210327142832422.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Tj8L7gP-1655909886920)(https://gitee.com/shao_ming314/picture/raw/master/image/image-20210327142851691.png)]
2.搭建项目
- springboot+mybatis脚手架
- application.properties配置文件内容如下
server.port=8080
spring.datasource.db1.username=root
spring.datasource.db1.password=root
spring.datasource.db1.jdbc-url=jdbc:mysql://127.0.0.1:3306/test?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
spring.datasource.db1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.db2.username=root
spring.datasource.db2.password=root
spring.datasource.db2.jdbc-url=jdbc:mysql://127.0.0.1:3306/yonghedb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
spring.datasource.db2.driver-class-name=com.mysql.cj.jdbc.Driver
#定义mybatis别名包
mybatis.type-aliases-package=com.shaoming.model.entity
#设置mapper.xml的文件位置
#开启驼峰
mybatis.configuration.map-underscore-to-camel-case=true
#处理返回map有null值得处理
mybatis.configuration.call-setters-on-nulls=true
logging.level.com.shaoming.mapper=debug
- 两个数据源配置类
package com.shaoming.config.datasource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
/**
* @author shaoming
* @Date: 2021/3/27 00:56
* @Description:
*/
@Configuration
@MapperScan(basePackages = {"com.shaoming.mapper.db1"},sqlSessionFactoryRef ="sqlSessionFactoryDb1" )
public class Db1Config {
@Autowired
@Qualifier("db1")
private DataSource dataSourceDb1;
@Bean
public SqlSessionFactory sqlSessionFactoryDb1() throws Exception{
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSourceDb1);
factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/db1/*.xml"));
return factoryBean.getObject();
}
@Bean
public SqlSessionTemplate sqlSessionTemplateDb1() throws Exception{
return new SqlSessionTemplate(sqlSessionFactoryDb1());
}
}
package com.shaoming.config.datasource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import javax.sql.DataSource;
/**
* @author shaoming
* @Date: 2021/3/27 01:52
* @Description:
*/
@Configuration
@MapperScan(basePackages = {"com.shaoming.mapper.db2"},sqlSessionFactoryRef ="sqlSessionFactoryDb2" )
public class Db2Config {
@Autowired
@Qualifier("db2")
private DataSource dataSourceDb2;
@Bean
public SqlSessionFactory sqlSessionFactoryDb2() throws Exception{
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSourceDb2);
factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/db2/*.xml"));
return factoryBean.getObject();
}
@Bean
public SqlSessionTemplate sqlSessionTemplateDb2() throws Exception{
return new SqlSessionTemplate(sqlSessionFactoryDb2());
}
}
- 数据源配置类
package com.shaoming.config.datasource;
/**
* @author shaoming
* @Date: 2021/3/27 01:01
* @Description:
*/
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
/**
* 由于我们禁掉了自动数据源配置,因些下一步就需要手动将这些数据源创建出来,创建DataSourceConfig类
*
*/
@Configuration
public class DataSourceConfig {
@Bean(name = "db1")
@ConfigurationProperties(prefix = "spring.datasource.db1")
public DataSource db1(){
return DataSourceBuilder.create().build();
}
@Bean(name = "db2")
@ConfigurationProperties(prefix = "spring.datasource.db2")
public DataSource db2(){
return DataSourceBuilder.create().build();
}
}
- 对应的两个mapper接口
DemoMapper.java
package com.shaoming.mapper.db1;
import com.shaoming.model.entity.Demo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @Auther: shaoming
* @Date: 2021/1/11 15:37
* @Description:
*/
@Mapper
public interface DemoMapper {
List<Demo> findAll();
}
DemoMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.shaoming.mapper.db1.DemoMapper">
<select id="findAll" resultType="com.shaoming.model.entity.Demo">
select * from demo
</select>
</mapper>
Demo2Mapper.java
package com.shaoming.mapper.db2;
import com.shaoming.model.entity.Demo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @Auther: shaoming
* @Date: 2021/1/11 15:37
* @Description:
*/
@Mapper
public interface Demo2Mapper {
List<Demo> findAll();
}
Demo2Mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.shaoming.mapper.db2.Demo2Mapper">
<select id="findAll" resultType="com.shaoming.model.entity.Demo">
select * from demo
</select>
</mapper>
3.项目整体目录
因为是基于目录进行多数据源的配置,所以大概的目录需要分清楚
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IxwYimRF-1655909886920)(https://gitee.com/shao_ming314/picture/raw/master/image/image-20210327143210645.png)]
4.测试
package com.shaoming;
import com.shaoming.mapper.db1.DemoMapper;
import com.shaoming.mapper.db2.Demo2Mapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author shaoming
* @Date: 2021/3/27 01:27
* @Description:
*/
@SpringBootTest
public class DaoTest {
@Autowired
private DemoMapper demoMapper;
@Autowired
private Demo2Mapper demo2Mapper;
@Test
public void testSelectnull(){
System.out.println(demoMapper.findAll());
System.out.println(demo2Mapper.findAll());
}
}
控制台打印:
[Demo(id=1, name=数据源1), Demo(id=2, name=数据源1), Demo(id=3, name=数据源1)]
…[Demo(id=1, name=数据源2), Demo(id=2, name=数据源2), Demo(id=3, name=数据源2)]
到此证明mybatis多数据源配置成功
37.springboot整合mybatis-plus多数据源配置
- 修改springboot的配置文件
把application.properties改为application.yml
具体内容如下
server:
port: 8080
spring:
datasource:
dynamic:
primary: master #设置默认的数据源或者数据源组,默认值即为master
strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源.
datasource:
master:
url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
slave_1:
url: jdbc:mysql://localhost:3306/yonghedb?serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
slave_2:
url: jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
- 引入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
- 写实体类
说明:
方便测试期间,我们就使用一个实体类
Emp.java
package com.shaoming;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
* @author shaoming
* @Date: 2021/3/28 15:57
* @Description:
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
@TableName("demo")
public class Demo {
@TableField("id")
@TableId(value = "id",type = IdType.AUTO)
private Integer id;
@TableField("name")
private String name;
}
3.写对应的3个mapper接口
DemoMasterMapper.java
package com.shaoming;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author shaoming
* @Date: 2021/3/28 15:59
* @Description:
*/
@Mapper
/**
* 指定是master数据源,当然也可以不指定,默认的就是master数据源
*/
@DS("master")
public interface DemoMasterMapper extends BaseMapper<Demo> {
}
DemoSalve1Mapper.java
package com.shaoming;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author shaoming
* @Date: 2021/3/28 15:59
* @Description:
*/
@Mapper
/**
* 指定的是slave_1数据源
*/
@DS("slave_1")
public interface DemoSalve1Mapper extends BaseMapper<Demo> {
}
DemoSalve2Mapper.java
package com.shaoming;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author shaoming
* @Date: 2021/3/28 15:59
* @Description:
*/
@Mapper
/**
* 指定的是slave_2数据源
*/
@DS("slave_2")
public interface DemoSalve2Mapper extends BaseMapper<Demo> {
}
1.@DS注解的介绍和使用
@DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解。
注解 | 结果 |
没有@DS | 默认数据源 |
@DS(“dsName”) | dsName可以为组名也可以为具体某个库的名称 |
2.测试
说明:
使用springboot的测试功能进行测试
package com.shaoming.springbootmpmoredatasource;
import com.shaoming.DemoMasterMapper;
import com.shaoming.DemoSalve1Mapper;
import com.shaoming.DemoSalve2Mapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author shaoming
* @Date: 2021/3/28 16:00
* @Description:
*/
@SpringBootTest
public class DaoTest {
@Autowired
private DemoMasterMapper demoMasterMapper;
@Autowired
private DemoSalve1Mapper demoSalve1Mapper;
@Autowired
private DemoSalve2Mapper demoSalve2Mapper;
@Test
public void testfindall() {
System.out.println("master数据源查出来的信息");
System.out.println(demoMasterMapper.selectList(null));
System.out.println("salve_1数据源查出来的信息");
System.out.println(demoSalve1Mapper.selectList(null));
System.out.println("salve_2数据源查出来的信息");
System.out.println(demoSalve2Mapper.selectList(null));
}
}
控制台打印:
master数据源查出来的信息
[Demo(id=1, name=数据源master), Demo(id=2, name=数据源master), Demo(id=3, name=数据源master)]
salve_1数据源查出来的信息
[Demo(id=1, name=数据源slave_1), Demo(id=2, name=数据源slave_1), Demo(id=3, name=数据源slave_1)]
salve_2数据源查出来的信息
[Demo(id=1, name=数据源slave_2), Demo(id=2, name=数据源slave_2), Demo(id=3, name=数据源slave_2)]
不指定master数据源进行测试
修改DemoMasterMapper.java内容
package com.shaoming;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* @author shaoming
* @Date: 2021/3/28 15:59
* @Description:
*/
@Mapper
/**
* 指定是master数据源,当然也可以不指定,默认的就是master数据源
*/
//@DS("master")
public interface DemoMasterMapper extends BaseMapper<Demo> {
}
修改的地方
去掉@DS(“master”)
控制台打印:
master数据源查出来的信息
[Demo(id=1, name=数据源master), Demo(id=2, name=数据源master), Demo(id=3, name=数据源master)]
salve_1数据源查出来的信息
[Demo(id=1, name=数据源slave_1), Demo(id=2, name=数据源slave_1), Demo(id=3, name=数据源slave_1)]
salve_2数据源查出来的信息
[Demo(id=1, name=数据源slave_2), Demo(id=2, name=数据源slave_2), Demo(id=3, name=数据源slave_2)]
结论:
如果使用注解指定数据源,默认的就是master数据源
38.原生ajax模板整理
1.ajax过程
说明:
这个可能是个面试题,问原生ajax的异步请求步骤
(1)创建XMLHttpRequest对象,也就是创建一个异步调用对象.
(2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息.
(3)设置响应HTTP请求状态变化的函数.
(4)发送HTTP请求.
(5)获取异步调用返回的数据.
(6)使用JavaScript和DOM实现局部刷新.
2.准备测试的接口
使用的是RAP接口在线测试工具
RAP官网网址:http://rap2.taobao.org/
测试的接口信息
get请求
url:http://rap2api.taobao.org/app/mock/261964/findall
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cDnQ8umY-1655909886920)(https://gitee.com/shao_ming314/picture/raw/master/image/image-20210328210957951.png)]
3.ajax测试模板
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style> /* 这里可以书写css样式 */
table{
border:2px solid red;
/* 设置表格的边框和单元格的边框合并 */
border-collapse: collapse;
/* 设置当前元素的左右外边距自适应,即设置
当前元素水平方向居中 */
margin-left:auto;
margin-right:auto;
/* 设置背景颜色 */
background: lightgrey;
}
td,th{
border:2px solid red;
/* 设置单元格的边框和内容之间的距离 */
padding:5px;
}
h1{
/* 让当前元素的内容居中显示 */
text-align: center;
}
</style>
</head>
<body>
<h1>Goods Ajax Pages</h1>
<div style="text-align: center;color: #000;">
<button id="btn1">点击发送原生的ajax</button>
</div>
<table>
<thead>
<tr>
<th>id</th>
<th>name</th>
<th>job</th>
<th>salary</th>
</tr>
</thead>
<tbody id="tbodyId">
<tr><td colspan="4">Data loading ...</td></tr>
</tbody>
</table>
<script type="text/javascript">
var btn = document.getElementById("btn1");
btn.onclick=function(){
alert("单击事件是否绑定成功!!!");
ajaxGet();
}
function ajaxGet(){
//页面加载完成向服务端再次发起请求,获取服务端数据,然后更新页面
//1.构建XHR对象并注册监听
var xhr=new XMLHttpRequest();
//注册监听函数(监听与服务端通讯过程)
xhr.onreadystatechange=function(){//callback
//readyState==4表示通讯结束
//status==200 表示服务端响应OK
if(xhr.readyState==4&&xhr.status==200){
//responseText表示服务端响应的结果
//console.log(xhr.responseText);//json格式字符串
//将服务端响应的json格式字符串,转换为json格式的JS对象
var result=JSON.parse(xhr.responseText);
doHandleResponseResult(result);
}
}
//2.建立连接
var url="http://rap2api.taobao.org/app/mock/261964/findall"
xhr.open("GET",url,true);//true代表异步
//3.发送请求
xhr.send(null);//get请求send方法内部不传参数
}
//处理响应结果
function doHandleResponseResult(result){
console.log(result);
//1.获得tbody对象,清空原有内容
var tBody=document.getElementById("tbodyId");
tBody.innerHTML="";
//2.迭代result记录,并将记录呈现在tbody位置
for(var i=0;i<result.length;i++){
//2.1构建tr对象
var tr=document.createElement("tr");
//2.2构建td对象,并追加到tr中
var td=document.createElement("td");
td.innerText=result[i].id;
tr.appendChild(td);
td=document.createElement("td");
td.innerText=result[i].name;
tr.appendChild(td);
td=document.createElement("td");
td.innerText=result[i].job;
tr.appendChild(td);
td=document.createElement("td");
td.innerText=result[i].salary;
tr.appendChild(td);
//2.3将tr对象追加到tbody中
tBody.appendChild(tr);
}
}
// ajaxGet();
</script>
</body>
</html>
4.测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aST8bDuY-1655909886920)(https://gitee.com/shao_ming314/picture/raw/master/image/image-20210328211129503.png)]
发送ajax请求的页面
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EW1qtASN-1655909886921)(https://gitee.com/shao_ming314/picture/raw/master/image/image-20210328211150656.png)]
39.springboot整合swagger+knife4j
准备工作
准备一个springboot的单体应用作为测试
1.整合swagger3.0
1.1引入依赖
<!--springfox swagger官方Starter-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
1.2添加配置类
package com.atguigu.yygh.hosp.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
/**
* Swagger2API文档的配置
* 访问地址
* http://localhost:端口号/swagger-ui/
* 我搭建项目喜欢使用springboot默认端口8080
* http://localhost:8080/swagger-ui/
*http://项目的ip地址:项目端口号/swagger-ui/
*/
@Configuration
public class Swagger2Config {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
/**
* 重点说明:
* 其余都是可以默认,但是controller扫描的路径一定要该队,是该项目的controller包路径
*/
.apis(RequestHandlerSelectors.basePackage("com.atguigu.yygh.hosp.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
/**
* 指定项目的名称和主题
*/
.title("xxxx演示")
/**
* 描述项目的用途
*/
.description("xxxxxdescription")
/**
* name:使用者的姓名
* url:使用者的相关技术文章
* email:使用者的邮箱地址
*/
.contact(new Contact("xxx", "xxxxx", "xxxxx"))
.version("1.0")
.build();
}
}
2.整合knife4j
说明:整合knif4j特别简单,引入一个依赖即可
引入依赖
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.2</version>
</dependency>
使用
1.访问网址
swagger3的访问网址
http://项目的ip地址:项目端口号/swagger-ui/
示例
localhost:8080/swagger-ui
knife4j访问网址
示例
localhost:8080/doc.html
40.springboot整合mybatis-plus逆向工程配置
简介
AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。
添加的依赖
<!-- springboot整合mybatis-plus逆向工程 -->
<!-- mybatis-plus逆向工程依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.2.0</version>
</dependency>
<!-- MyBatis-Plus 支持 Velocity(默认) -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
代码模板
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import java.util.ArrayList;
/**
* @author shaoming
* @Date: 2021/4/8 12:00
* @Description:
*/
// 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中
public class CodeGenerator {
public static void main(String[] args) {
// 需要构建一个 代码自动生成器 对象
AutoGenerator mpg = new AutoGenerator();
// 配置策略
// 1、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath+"/src/main/java");
gc.setAuthor("kwhua");//作者名称
gc.setOpen(false);
gc.setFileOverride(false); // 是否覆盖
gc.setIdType(IdType.AUTO);
gc.setDateType(DateType.ONLY_DATE);
gc.setSwagger2(true);//实体属性 Swagger2 注解
// 自定义文件命名,注意 %s 会自动填充表实体属性!
gc.setServiceName("%sService");
gc.setControllerName("%sController");
gc.setServiceName("%sService");
gc.setServiceImplName("%sServiceImpl");
gc.setMapperName("%sMapper");
gc.setXmlName("%sMapper");
mpg.setGlobalConfig(gc);
//2、设置数据源
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/yygh_hosp?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver"); //mysql5.6以下的驱动
dsc.setUsername("root");
dsc.setPassword("root");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
//3、包的配置
PackageConfig pc = new PackageConfig();
pc.setParent("com.atguigu.yygh.hosp.utils"); //包名
pc.setModuleName("codegenerator"); //模块名
pc.setEntity("entity");
pc.setMapper("mapper");
pc.setService("service");
pc.setController("controller");
mpg.setPackageInfo(pc);
//4、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("user"); // 设置要映射的表名
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true); // 自动lombok;
strategy.setLogicDeleteFieldName("deleted");
// 自动填充配置
TableFill gmtCreate = new TableFill("create_time", FieldFill.INSERT);
TableFill gmtModified = new TableFill("update_time",FieldFill.INSERT_UPDATE);
ArrayList<TableFill> tableFills = new ArrayList<>();
tableFills.add(gmtCreate);
tableFills.add(gmtModified);
strategy.setTableFillList(tableFills);
// 乐观锁
strategy.setVersionFieldName("version");
//根据你的表名来建对应的类名,如果你的表名没有下划线,比如test,那么你就可以取消这一步
strategy.setTablePrefix("t_");
strategy.setRestControllerStyle(true); //rest请求
//自动转下划线,比如localhost:8080/hello_id_2
strategy.setControllerMappingHyphenStyle(true);
strategy.setSuperEntityClass("BaseEntity");
mpg.setStrategy(strategy);
mpg.execute(); //执行
}
}
需要注意的配置项
1.是否添加swagger注解配置项
现在一般项目都是整合了swagger接口工具,所以我们一般需要添加swagger注解,添加此注解无侵害性
gc.setSwagger2(true);//实体属性 Swagger2 注解
2.配置数据库连接信息
dsc.setUrl("jdbc:mysql://localhost:3306/yygh_hosp?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
// dsc.setDriverName("com.mysql.jdbc.Driver"); //mysql5.6以下的驱动
dsc.setUsername("root");
dsc.setPassword("root");
说明:
jdbc连接信息使用
useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
防止出现时区差异或者中文乱码
3.指定主键自增的类型
gc.setIdType(IdType.AUTO);
4.指定模板引擎
说明:
添加 模板引擎 依赖,MyBatis-Plus 支持 Velocity(默认)、Freemarker、Beetl,用户可以选择自己熟悉的模板引擎,如果都不满足您的要求,可以采用自定义模板引擎
我们就是用mybatis-plus的默认引擎,在项目中添加如下依赖
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
5.设置自动填充和乐观锁
说明:
自动填充,乐观锁的列明要和实体类的属性名一致
//自动填充
TableFill gmtCreate = new TableFill("create_time", FieldFill.INSERT);
TableFill gmtModified = new TableFill("update_time",FieldFill.INSERT_UPDATE);
ArrayList<TableFill> tableFills = new ArrayList<>();
tableFills.add(gmtCreate);
tableFills.add(gmtModified);
strategy.setTableFillList(tableFills);
// 乐观锁
strategy.setVersionFieldName("version");
5.设置需要生成的表名
说明:
需要生成的表名和数据库一致,可以同事生成多个表的逆向文件
strategy.setInclude("user"); // 设置要映射的表名
6.设置包名和模块名
具体根据情况而定
pc.setParent("com.mybatis-plus"); //包名
pc.setModuleName("genertor"); //模块名
7.设置实体类继承的实体类
strategy.setSuperEntityClass("BaseEntity");
踩坑记录
报错信息
ClassNotFoundException: com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator
原因
mybatis-plus-generator包和mybatis-plus-boot-starter包版本不对应
41.springmvc四种类型返回值
对应测试的controller
TestController
import com.example.demo.demos.model.Book;
import com.example.demo.demos.model.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author shaoming
* @Date: 2021/4/9 17:18
* @Description:
*/
@Controller
public class TestController {
@RequestMapping("book")//get请求
// @ResponseBody
/**
* 返回值为ModelAndView
*/
public ModelAndView getAllBook() {
ModelAndView mv = new ModelAndView();
List<Book> books = new ArrayList<Book>();
Book b1 = new Book();
b1.setId(1).setAuthor("罗贯中").setName("三国演义");
Book b2 = new Book();
b2.setId(2).setAuthor("曹雪芹").setName("红楼梦");
books.add(b1);
books.add(b2);
mv.addObject("bs", books);
mv.setViewName("book");
return mv;
}
/**
* 返回值为void类型
*/
@RequestMapping("/test2")//get请求
@ResponseBody
public void test2() {
//你的代码
System.out.println("controller方法时没有返回值");
}
/**
* 返沪void类型的重定向,通过status和header进行设置(不常用)
* @param resp
* @throws IOException
*/
@RequestMapping("/test1")//get请求
@ResponseBody
public void test1(HttpServletResponse resp) {
resp.setStatus(302);
resp.addHeader("Location", "/book");
}
/**
* 返沪void类型的重定向
* @param resp
* @throws IOException
*/
@RequestMapping("/test11")//get请求
@ResponseBody
public void test11(HttpServletResponse resp) throws IOException {
resp.sendRedirect("/book");
}
@RequestMapping("/test5")//get请求
@ResponseBody
public void test5(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
req.getRequestDispatcher("/book").forward(req, resp);
}
/**
* 返回值为void,并页面输出json格式字符窜
* @param resp
* @throws IOException
*/
@RequestMapping("/test3")//get请求
@ResponseBody
public void test3(HttpServletResponse resp) throws IOException {
/**
* 设置响应的数据为json格式
*/
resp.setContentType("application/json;charset=utf8");
PrintWriter out = resp.getWriter();
List<Book> books = new ArrayList<Book>();
Book b1 = new Book();
b1.setId(1).setAuthor("罗贯中").setName("三国演义");
Book b2 = new Book();
b2.setId(2).setAuthor("曹雪芹").setName("红楼梦");
books.add(b1);
books.add(b2);
/**
* 通过jackson工具类把java对象转为json格式的字符窜
*/
String booksJson = new ObjectMapper().writeValueAsString(books);
out.write(booksJson);
out.flush();
out.close();
}
/**
* 返回视图名称并通过model获取数据
* @param model
* @return
*/
@RequestMapping("/test4")
public String test4(Model model) {
Book b1 = new Book();
b1.setId(1).setAuthor("罗贯中").setName("三国演义");
model.addAttribute("book", b1);
model.addAttribute("username", "张三");
return "bookinfo";
}
/**
* 返回string类型的重定向
* @return
*/
@RequestMapping("/test6")
public String test6() {
return "redirect:/book";
}
/**
* 返回string类型的转发
* @return
*/
@RequestMapping("/test7")
public String test7() {
return "forward:/book";
}
/**
* 返回json
* @return
*/
@GetMapping("/user")//get请求
@ResponseBody
public User getUser() {
User user = new User();
List<String> favorites = new ArrayList<>();
favorites.add("足球");
favorites.add("篮球");
user.setFavorites(favorites).setUsername("张三").setPassword("123456");
return user;
}
@GetMapping("/users")//get请求
@ResponseBody
public List<User> getUsers() {
List<User> users = new ArrayList<>();
for (int i = 0; i < 10; i++) {
User user = new User();
user.setPassword("张三" + i).setPassword("pwd" + i)
.setFavorites(new ArrayList<String>(Arrays.asList("football", "basketball")));
users.add(user);
}
return users;
}
}
测试的模板引擎页面(使用的是thymeleaf模板引擎)
book.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap 101 Template</title>
<!-- Bootstrap -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
rel="stylesheet">
<script
src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
<style type="text/css">
#div2{
text-align: center;
border: 3px solid red;
}
a{
font-size: 25px;
}
</style>
</head>
<body>
<!-- 查询所有员工列表页面 -->
<h1 align="center">book列表信息</h1>
<!-- 这个表格示显示员工数据的 -->
<div id="div2">
<table class="table table-condensed">
<thead>
<tr>
<td>编号</td>
<td>ID</td>
<td>NAME</td>
<td>JOB</td>
</thead>
<tbody>
<tr th:each="book,varstatus:${bs}">
<td th:text="${varstatus.count}"></td>
<td th:text="${book.id}"></td>
<td th:text="${book.name}"></td>
<td th:text="${book.author}"></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
bookinfo.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Getting Started: Serving Web Content</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'页面获取model的username的值为: , ' + ${username} + '!'" />
<hr>
<hr>
<p th:text="'页面获取model的book的信息book的id为: , ' + ${book.id}" />
<p th:text="'页面获取model的book的信息book的author为: , ' + ${book.author}" />
<p th:text="'页面获取model的book的信息book的name为: , ' + ${book.name} " />
</body>
</html>
42.springcache+redis 缓存数据
- 引入依赖
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- spring2.X集成redis所需common-pool2-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.6.0</version>
</dependency>
- 编写redis配置类
@Configuration
@EnableCaching
public class RedisConfig {
/**
* 自定义key规则
* @return
*/
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
/**
* 设置RedisTemplate规则
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
//序列号key value
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/**
* 设置CacheManager缓存规则
* @param factory
* @return
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置序列化(解决乱码的问题),过期时间600秒
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(600))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
}
- 标签解释
@Cacheable
根据方法对其返回结果进行缓存,下次请求时,如果缓存存在,则直接读取缓存数据返回;如果缓存不存在,则执行方法,并把返回的结果存入缓存中。一般用在查询方法上。
@CachePut
使用该注解标志的方法,每次都会执行,并将结果存入指定的缓存中。其他方法可以直接从响应的缓存中读取缓存数据,而不需要再去查询数据库。一般用在新增方法上。
@CacheEvic
使用该注解标志的方法,会清空指定的缓存。一般用在更新或者删除方法上
- 示例代码
/**
* 根据上级id获取子节点数据列表
* @param parentId
*/
@Cacheable(value = "dict",keyGenerator = "keyGenerator")
@Override
public List<Dict> findByParentId(Long parentId) {
List<Dict> dictList = dictMapper.selectList(new QueryWrapper<Dict>().eq("parent_id", parentId));
dictList.stream().forEach(dict -> {
boolean isHasChildren = this.isHasChildren(dict.getId());
dict.setHasChildren(isHasChildren);
});
return dictList;
}
/**
* 导入
* allEntries = true: 方法调用后清空所有缓存
* @param file
*/
@CacheEvict(value = "dict", allEntries=true)
@Override
public void importData(MultipartFile file) {
ExcelHelper fileHelper = new ExcelHelper(DictEeVo.class);
List<DictEeVo> dictVoList = fileHelper.importExcel(file);
if(!CollectionUtils.isEmpty(dictVoList)) {
dictMapper.insertBatch(dictVoList);
}
}
43.StringUtils和StrUtil(Hutool)常用操作字符窜方法使用模板
整理原因
springboot的StringUtils几个方法怎么判空总是分不清楚,整理好了就可以很好的使用
import cn.hutool.core.util.StrUtil;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.util.StringUtils;
/**
* @author shaoming
* @Date: 2021/4/25 09:21
* @Description:
*/
public class StringUtilsTest {
/**
* @author shaoming
* @Date: 2021/4/23 16:47
* @Description:
*/
@SpringBootTest
public static class StringUitilTest {
@Test
public void testCreateString() {
String str1 = "";
String str2 = " ";
String str3 = null;
String str4 = " 我是string的内容 ";
}
/**
* 测试org.springframework.util.StringUtils工具判断字符窜是否为空的api
*/
@Test
public void testStringNotEmptyBySpringUtils() {
String str1 = "";
String str2 = " ";
String str3 = null;
String str4 = " 我是string的内容 ";
boolean empty1 = StringUtils.isEmpty(str1);
boolean empty2 = StringUtils.isEmpty(str2);
boolean empty3 = StringUtils.isEmpty(str3);
boolean empty4 = StringUtils.isEmpty(str4);
System.out.println(empty1);
System.out.println(empty2);
System.out.println(empty3);
System.out.println(empty4);
/*
控制台打印:
true
false
true
false
*/
}
/**
* org.apache.commons.lang3.StringUtils这个工具类进行字符窜判空的工具类
* 说明:
* 使用这个工具类需要引入以下依赖
* <dependency>
* <groupId>org.apache.commons</groupId>
* <artifactId>commons-lang3</artifactId>
* <version>3.1</version>
* </dependency>
*/
@Test
public void testStirngNotEmptyByapacheCommonsLangsStringUtils() {
String str1 = "";
String str2 = " ";
String str3 = null;
String str4 = " 我是string的内容 ";
System.out.println("测试isBlank方法");
System.out.println(org.apache.commons.lang3.StringUtils.isBlank(str1));
System.out.println(org.apache.commons.lang3.StringUtils.isBlank(str2));
System.out.println(org.apache.commons.lang3.StringUtils.isBlank(str3));
System.out.println(org.apache.commons.lang3.StringUtils.isBlank(str4));
System.out.println("测试isEmpty方法");
System.out.println(org.apache.commons.lang3.StringUtils.isEmpty(str1));
System.out.println(org.apache.commons.lang3.StringUtils.isEmpty(str2));
System.out.println(org.apache.commons.lang3.StringUtils.isEmpty(str3));
System.out.println(org.apache.commons.lang3.StringUtils.isEmpty(str4));
/*
* 控制台打印
* 测试isBlank方法
* true
* true
* true
* false
* 测试isEmpty方法
* true
* false
* true
* false
*/
}
/**
* 测试hutool的String判空工具类
* 说明:
* 使用StrUtil需要在mavne项目中引入hutool的依赖
* <dependency>
* <groupId>cn.hutool</groupId>
* <artifactId>hutool-all</artifactId>
* <version>5.6.3</version>
* </dependency>
*/
@Test
public void testStringByHutoolofStrUtil() {
String str1 = "";
String str2 = " ";
String str3 = null;
String str4 = " 我是string的内容 ";
System.out.println("测试hutool中String判空的isBlank方法");
System.out.println(StrUtil.isBlank(str1));
System.out.println(StrUtil.isBlank(str2));
System.out.println(StrUtil.isBlank(str3));
System.out.println(StrUtil.isBlank(str4));
System.out.println("测试hutool中String判空的isEmpty方法");
System.out.println(StrUtil.isEmpty(str1));
System.out.println(StrUtil.isEmpty(str2));
System.out.println(StrUtil.isEmpty(str3));
System.out.println(StrUtil.isEmpty(str4));
/*
* 控制台打印
* 测试hutool中String判空的isBlank方法
* true
* true
* true
* false
* 测试hutool中String判空的isEmpty方法
* true
* false
* true
* false
*/
}
}
}
44.测试跨域的html页面
cros.html
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body>
<h2>Hello World!</h2>
<script type="text/javascript">
function fun1(){
var request = new XMLHttpRequest();
request.open("GET","http://www.shaoming.club:80/app/center/getsysconfigbygroup")
request.send();
request.onreadystatechange = function(){
if(request.status==200 && request.readyState == 4){
console.log("响应的结果" + request.responseText)
}
}
}
</script>
</body>
<input type="button" value="跨域调用" onclick="fun1()">
</html>
说明:
使用原生ajax发送请求,只要满足跨域条件我们发送ajax请求就成功返回json数据
如果成功,证明后端接口做了跨域处理
45.springboot整合knife4j(快速通用版)
引入pom.依赖
<!-- springboot整合knife4j依赖(低版本也可以用1.5.xx版本以后都是可用) -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.4</version>
</dependency>
swagger配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {
@Bean(value = "defaultApi2")
public Docket defaultApi2() {
Docket docket=new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.groupName("低版本版本")
.select()
.apis(RequestHandlerSelectors.basePackage("com.jsbs.ordergood.controller"))
//.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build();
return docket;
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("swagger-bootstrap-ui-demo RESTful APIs")
.description("# swagger-bootstrap-ui-demo RESTful APIs")
.termsOfServiceUrl("http://www.xx.com/")
.contact("xx@qq.com")
.version("1.0")
.build();
}
}
knife4j访问网址
说明:
apis(RequestHandlerSelectors.basePackage("com.xiaominfo.knife4j.demo.web"))指定对应controller包路劲即可
46.maven配置阿里云镜像的两种方式
配置方式
第一种方式(settings.xml文件)
在mirrors节点下加入一个新的mirror节点,配置阿里镜像地址,完整配置如下:
<mirrors>
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
第二种方式(pom.xml方式)
修改项目pom.xml,在repositories节点下加入repository节点,配置阿里镜像地址,完整配置如下:
此配置参考renren-genertor项目的pom.xml配置,项目网址:https://gitee.com/renrenio/renren-generator
<repositories>
<repository>
<id>public</id>
<name>aliyun nexus</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>aliyun nexus</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
区别
第一种方式是全局的方式配置
第二种方式只能当前项目生效
47.Vagrantfile模板
说明:
vagrant 安装 centos7 的模板
# -*- mode: ruby -*-
# vi: set ft=ruby :
# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.
# Every Vagrant development environment requires a box. You can search for
# boxes at https://vagrantcloud.com/search.
config.vm.box = "centos/7"
# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. This is not recommended.
# config.vm.box_check_update = false
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
# NOTE: This will enable public access to the opened port
# config.vm.network "forwarded_port", guest: 80, host: 8080
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine and only allow access
# via 127.0.0.1 to disable public access
# config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
# Create a private network, which allows host-only access to the machine
# using a specific IP.
config.vm.network "private_network", ip: "192.168.56.10"
# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
# config.vm.network "public_network"
# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
# config.vm.synced_folder "../data", "/vagrant_data"
# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
# Example for VirtualBox:
#
# config.vm.provider "virtualbox" do |vb|
# # Display the VirtualBox GUI when booting the machine
# vb.gui = true
#
# # Customize the amount of memory on the VM:
# vb.memory = "1024"
# end
#
# View the documentation for the provider you are using for more
# information on available options.
# Enable provisioning with a shell script. Additional provisioners such as
# Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
# documentation for more information about their specific syntax and use.
# config.vm.provision "shell", inline: <<-SHELL
# apt-get update
# apt-get install -y apache2
# SHELL
# 设置 虚拟机的内存和cpu核数
config.vm.provider "virtualbox" do |v|
v.memory = 2048
v.cpus = 2
end
end
48.springboot使用undertow代替tomcat
参考网址:
若依文档使用使用undertow来替代tomcat容器
两者对比
SpingBoot
中我们既可以使用Tomcat
作为Http
服务,也可以用Undertow
来代替。Undertow
在高并发业务场景中,性能优于Tomcat
。所以,如果我们的系统是高并发请求,不妨使用一下Undertow
,你会发现你的系统性能会得到很大的提升。
1、ruoyi-framework\pom.xml
模块修改web容器依赖,使用undertow来替代tomcat容器
<!-- SpringBoot Web容器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- web 容器使用 undertow -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
2、修改application.yml
,使用undertow来替代tomcat容器
# 开发环境配置
server:
# 服务器的HTTP端口,默认为80
port: 80
servlet:
# 应用的访问路径
context-path: /
# undertow 配置
undertow:
# HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的
max-http-post-size: -1
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
# 每块buffer的空间大小,越小的空间被利用越充分
buffer-size: 512
# 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
io-threads: 8
# 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
worker-threads: 256
# 是否分配的直接内存
direct-buffers: true
nginx 配置 http
参考网址:
参数说明:
cloud.tencent.com_bundle.crt 证书文件
cloud.tencent.com_bundle.pem 证书文件(可忽略该文件)
cloud.tencent.com.key 私钥文件
cloud.tencent.com.csr CSR 文件
基础模板
server {
#SSL 访问端口号为 443
listen 443 ssl;
#填写绑定证书的域名
server_name cloud.tencent.com;
#证书文件名称
ssl_certificate cloud.tencent.com_bundle.crt;
#私钥文件名称
ssl_certificate_key cloud.tencent.com.key;
ssl_session_timeout 5m;
#请按照以下协议配置
ssl_protocols TLSv1.2 TLSv1.3;
#请按照以下套件配置,配置加密套件,写法遵循 openssl 标准。
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
#网站主页路径。此路径仅供参考,具体请您按照实际目录操作。
#例如,您的网站运行目录在/etc/www下,则填写/etc/www。
root html;
index index.html index.htm;
}
}
http 重定向到 https 模板
server {
#SSL 访问端口号为 443
listen 443 ssl;
#填写绑定证书的域名
server_name cloud.tencent.com;
#证书文件名称
ssl_certificate cloud.tencent.com_bundle.crt;
#私钥文件名称
ssl_certificate_key cloud.tencent.com.key;
ssl_session_timeout 5m;
#请按照以下协议配置
ssl_protocols TLSv1.2 TLSv1.3;
#请按照以下套件配置,配置加密套件,写法遵循 openssl 标准。
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
#网站主页路径。此路径仅供参考,具体请您按照实际目录操作。
#例如,您的网站运行目录在/etc/www下,则填写/etc/www。
root html;
index index.html index.htm;
}
}
halo 博客 和 docsify 的 https 配置模板
halo博客使用 https
docsify 知识库文档使用 http
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
#gzip on;
# another virtual host using mix of IP-, name-, and port-based configuration
#
# HTTPS server
upstream halo {
server 127.0.0.1:8090;
}
server {
listen 8080;
location / {
root /opt/docsify/;
index index.html index.html;
}
}
server {
#SSL 访问端口号为 443
listen 443 ssl;
#填写绑定证书的域名
server_name cloud.tencent.com;
#证书文件名称
ssl_certificate www.shaoming.club.crt;
#私钥文件名称
ssl_certificate_key www.shaoming.club.key;
ssl_session_timeout 5m;
#请按照以下协议配置
ssl_protocols TLSv1.2 TLSv1.3;
#请按照以下套件配置,配置加密套件,写法遵循 openssl 标准。
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
gzip_static on; # 静态压缩
add_header Cache-Control public,max-age=60,s-maxage=60; # 配置缓存
proxy_pass http://127.0.0.1:8090;
proxy_set_header HOST $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
server {
listen 80;
server_name localhost;
#将请求转成https
#rewrite ^(.*)$ https://$host$1 permanent; # 另一种方式 ,不建议使用 , 下面使用是腾讯云方案
return 301 https://$host$request_uri;
}
}
halo 博客 和 docsify 的 http 配置模板
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
#gzip on;
upstream halo {
server 127.0.0.1:8090;
}
server {
listen 80;
listen [::]:80;
server_name www.shaoming.club;
client_max_body_size 1024m;
location / {
gzip_static on; # 静态压缩
add_header Cache-Control public,max-age=60,s-maxage=60; # 配置缓存
proxy_pass http://halo;
proxy_set_header HOST $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
server {
listen 8080;
location / {
root /opt/docsify/;
index index.html index.html;
}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}