待完成:
nexus 本地仓库,上传下载jar包
jwt解析
https://www.codesheep.cn/2019/03/14/security-jwt-hibernate/
表定义,数据库表迁移、更新
https://flywaydb.org/getstarted/firststeps/maven#creating-the-first-migration
字段唯一,unique_together
unique_together = (('type_name', 'capability_name'))
查询:
精确(UserCopy1Example.andDescriptionEqualTo) done
模糊(UserCopy1Example.andDescriptionLike) done
条件排序(UserCopy1Example.orderByClause) done
枚举:done
https://blog.csdn.net/qq_27093465/article/details/52180865
https://blog.csdn.net/houyefeng/article/details/45886613
https://blog.csdn.net/chidi5109/article/details/100599083
https://blog.csdn.net/zangdaiyang1991/article/details/86518088
https://blog.csdn.net/qq_26440803/article/details/83451221
https://www.cnblogs.com/dalianpai/p/11771269.html
路由管理、请求处理
https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#webmvc-fn-router-functions
@Temporal(TemporalType.TIMESTAMP)
@Column
@JsonProperty("create_time")
@JsonDeserialize(using = EventCreateTimeDeserializer.class)
@JsonSerialize(using = EventCreateTimeSerializer.class)
@TableField(typeHandler = EventCreateTimeHandler.class)
@Future(message = "时间在当前时间之后才可以通过")
private java.util.Date createTime;
post http://localhost:9000/log/
EventCreateTimeDeserializer.deserialize
Entity:
setCreateTime
setLevel
@Future(message = "时间在当前时间之后才可以通过")
private java.util.Date createTime;
getEffectiveTemporalValidationTolerance
FutureValidatorForDate.getInstant
AbstractFutureInstantBasedValidator.is_valid
EventLevelValidator
long id = this.getBaseMapper().insert(event);
getCreateTime
[2020-02-13 14:57:42.646] [DEBUG]
EventCreateTimeHandler.setParameter
EventLevelHandler.setParameter
return this.getById(event.getId());
setCreateTime、setLevel
EventCreateTimeSerializer.serialize
controller(RestController),model(Entity、Domain),view
小马哥:第6章 Web MVC REST 应用
https://coding.imooc.com/class/chapter/252.html#Anchor
数据校验:
https://mp.weixin.qq.com/s?__biz=MzUxOTc4NjEyMw==&mid=2247484258&idx=1&sn=a88dd960fd183f2f834a96489d643583&chksm=f9f51886ce829190645896f86083183d69066698a1264bcdd8784dabf03f5c0b7d2c50408701&mpshare=1&scene=24&srcid=0517wvmU7j3SiGApLmBIq44I#rd
https://blog.csdn.net/Howinfun/article/details/90287047
https://blog.csdn.net/huangdi1309/article/details/89673875
小马哥:第十二节 验证 (课件) [问答]
序列化和反序列化
小马哥:第6章 Web MVC REST 应用
https://coding.imooc.com/class/chapter/252.html#Anchor/
accessing-data-mysql
https://spring.io/guides/gs/accessing-data-mysql/
CRUD
外键关联(一对一,多对一,多对多,外键删除行为:CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET):
分页(userCopy1Repository.getPageList(page, pageSize),
PagingAndSortingRepository)
https://github.com/pagehelper/Mybatis-PageHelper
批量操作、删除 (SimpleJpaRepository)
第八节 Java Persistence API (课件) (注意:此处只是实现功能,由于jpa做了很多封装,考虑性能的话还是要用mybatis)
原子操作 ?
.setCommit(false)
.setCommit(true)
https://segmentfault.com/n/1330000009887617
自定义response
https://blog.csdn.net/shenszy/article/details/85676415
httpClient
RestTemplate
createTime--> create_time
异步
http://www.spring4all.com/article/540
未实现,遇到问题:
spring boot2 EnableAysnc If the controller requires proxying (e.g. due to @Transactional), please us
打包
1 jar 命令行运行
java -jar target\msgcenter-0.0.1-SNAPSHOT.jar
2 war tmocat容器中运行,设置如如下:
部署
docker
http://www.spring4all.com/article/557
application.yml
# Logger Config
logging:
level:
root: info # 全局
ik.starriver.msgcenter: debug # 包级别
pattern:
console: '%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){magenta} %clr([%5p]) %highlight(%C:%L) %m %n'
file: '%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){magenta} %clr([%5p]) %highlight(%C:%L) %m %n'
# 默认日志文件名
file: test.log
# 默认日志路径
path: ./log
# logback.xml路径,默认为classpath:logback.xml
# config: ./logback.xml
#app
server:
port: 9000
#spring
spring:
output:
ansi:
enabled: ALWAYS
devtools:
restart:
enabled: false
# mysql DATABASE CONFIG
datasource:
# 使用druid数据源
# type: com.alibaba.druid.pool.DruidDataSource
type: org.apache.commons.dbcp2.BasicDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://10.1.252.23:3306/springtest?serverTimezone=UTC
username: root
password: 123456
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
# dbcp2
dbcp2:
url: jdbc:mysql://10.1.252.23:3306/springtest?serverTimezone=UTC
username: root
password: '%tBqnWF1y3ku'
maxTotal: 20
maxIdle: 5
driverClassName: com.mysql.cj.jdbc.Driver
jpa:
open-in-view: false
database: MYSQL
databasePlatform: org.hibernate.dialect.MySQL5InnoDBDialect
generateDdl: true
hibernate:
ddlAuto: update
#mybatis
mybatis-plus:
mapper-locations: classpath:/mapper*/*Mapper.xml
#实体扫描,多个package用逗号或者分号分隔
typeAliasesPackage: ik.starriver.msgcenter.entity
# typeEnumsPackage: com.baomidou.springboot.entity.enums
global-config:
# 数据库相关配置
db-config:
# table-prefix: tianshu_log_
#主键类型 AUTO:"数据库ID自增", INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
# id-type: ASSIGN_ID
#字段策略 IGNORED:"忽略判断",NOT_NULL:"非 NULL 判断"),NOT_EMPTY:"非空判断"
field-strategy: not_empty
#驼峰下划线转换
column-underline: true
#数据库大写下划线转换
#capital-mode: true
#逻辑删除配置
logic-delete-value: 0
logic-not-delete-value: 1
db-type: mysql
#刷新mapper 调试神器
refresh: true
# 原生配置
configuration:
map-underscore-to-camel-case: true
cache-enabled: false
pom.xml
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.3.0.M1
ik.starriver
msgcenter
0.0.1-SNAPSHOT
msgcenter
msgcenter project for starriver
1.8
3.3.1
starriver
org.apache.commons
commons-dbcp2
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-starter-validation
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-jpa
org.springframework.boot
spring-boot-starter-jdbc
mysql
mysql-connector-java
runtime
com.fasterxml.jackson.dataformat
jackson-dataformat-xml
org.springframework.boot
spring-boot-starter-test
test
org.junit.vintage
junit-vintage-engine
com.baomidou
mybatis-plus-boot-starter
${mybatis-plus-boot-starter.version}
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-maven-plugin
spring-milestones
Spring Milestones
https://repo.spring.io/milestone
spring-milestones
Spring Milestones
https://repo.spring.io/milestone
打包:
D:\shen\java\webdevelop\spring\msgcenter>java -jar target\msgcenter-0.0.1-SNAPSHOT.jar
上传jar包到部署环境:
Dockerfile
命令行方式:docker run -e "JAVA_OPTS=-Xmx52m" app-image
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ADD msgcenter-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 9000
ENV JAVA_OPTS="-Xmx52m"
ENV DATABASE_URL="--spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springtest"
ENV DATABASE_USERNAME="--spring.datasource.username=root"
ENV DATABASE_PASSWORD="--spring.datasource.password=123456"
ENTRYPOINT exec java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $DATABASE_URL $DATABASE_USERNAME $DATABASE_PASSWORD
# 启动命令模式为:exec java $JAVA_OPTS(jvm的参数) xxx-app.jar $SPRING_OPTIONS(spring的参数)
docker-compose.yml
[root@shen msgcenter]# cat docker-compose.yml
version: "3"
services:
web:
build: .
image: msgcenter
ports: ['9000:9000']
#command: ["/bin/bash", "start.sh"]
# command: ["uwsgi", "--ini", "uwsgi.ini"]
#environment:
# - ALLOW_HOST=*
#- DB_HOST=10.1.252.23
#- DB_PORT=3306
#- DB_USER=root
#- DB_PASSWORD=%tBqnWF1y3ku
#- DB_NAME=tianshu_data_dict
# volumes: ['.:/code']
docker-deploy.py
[root@shen msgcenter]# cat docker-deploy.py
import re
import os
DOCKER_COMPOSE_IMAGE_NAME = "msgcenter"
def stop_container():
p = os.popen('docker ps')
output = p.read()
# print(output)
pattern = re.compile(".*{}".format(DOCKER_COMPOSE_IMAGE_NAME))
try:
container_id = re.search(pattern, output).group().split()[0]
if not container_id:
return
p = os.popen('docker stop {}'.format(container_id))
output = p.read()
print("docker stop {}".format(output))
except (AttributeError, ) as e:
print("stop_container: {}".format(str(e)))
def docker_compose():
p = os.popen('docker-compose up -d --build')
output = p.read()
print(output)
def docker_ps():
print("------------------")
docker_ps_cmd = 'docker ps|grep {}'.format(DOCKER_COMPOSE_IMAGE_NAME)
print(docker_ps_cmd)
p = os.popen(docker_ps_cmd)
output = p.read()
print(output)
if __name__ == "__main__":
stop_container()
docker_compose()
docker_ps()
生成 image,并启动docker
[root@shen msgcenter]# python3 docker-deploy.py
PS:
cli动态传入全局变量的方式:
D:\shen\java\webdevelop\spring\log>java -jar target\log-0.0.1-SNAPSHOT.jar
--spring.datasource.url=
jdbc:mysql://10.1.252.23:3306/springisp?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf8
--spring.profiles.active=pro
--spring.datasource.username=root
--spring.datasource.password=123456
官网部署文档
https://docs.spring.io/spring-boot/docs/current/reference/html/deployment.html#containers-deployment
FROM openjdk:8-jdk-alpine AS builder
WORKDIR target/dependency
ARG APPJAR=target/*.jar
COPY ${APPJAR} app.jar
RUN jar -xf ./app.jar
FROM openjdk:8-jre-alpine
VOLUME /tmp
ARG DEPENDENCY=target/dependency
COPY --from=builder ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=builder ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=builder ${DEPENDENCY}/BOOT-INF/classes /app
ENTRYPOINT ["java","-cp","app:app/lib/*","com.example.MyApplication"]
JDBC 与 MySQL 的这种误解,导致出现了数据库实际存储的时间戳,与业务系统取到的值差了 13 或者 14 个小时,这个时间与美中是(=13)否(=14)采用夏令时息息相关。
解决:
mysql> set global time_zone = '+08:00';
Query OK, 0 rows affected (0.00 sec)
mysql> set time_zone = '+08:00';
Query OK, 0 rows affected (0.00 sec)
https://blog.csdn.net/qq_30553235/article/details/79612824
restdocs
https://www.cnblogs.com/qq350760546/p/8397557.html
https://docs.spring.io/spring-restdocs/docs/2.0.4.RELEASE/reference/html5/#introduction
http://www.spring4all.com/article/3333
http请求构造类:
RestTemplate
@Test
public void test() {
final String url = "http://localhost:9000/log/?page=2&pageSize=2&orderBy=level&direction=desc&searchName=content&searchValue=con&nameLike=true";
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Content-Type", MediaType.APPLICATION_JSON_VALUE);
requestHeaders.add("Authorization", "Bearer test");
RestTemplate template = new RestTemplate();
HttpEntity requestEntity = new HttpEntity(null, requestHeaders);
ResponseEntity response = template.exchange(url, HttpMethod.GET, requestEntity, String.class);
String result = response.getBody();
System.err.println(result);
}
MockMvc
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureRestDocs(uriPort = 9000)
public class RestControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
void testGetEventPage() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.put("Content-Type", Arrays.asList(MediaType.APPLICATION_JSON_VALUE));
headers.put("Authorization", Arrays.asList("Bearer dXNlcjpzZWNyZXQ="));
this.mockMvc.perform(get("/log/?page=2&pageSize=2&orderBy=level&direction=desc&searchName=content&searchValue=con&nameLike=true").headers(headers))
.andExpect(status().isOk())
.andDo(document("eventPage",
requestHeaders(
headerWithName("Content-Type").description(
"desc Content-Type"),
headerWithName("Authorization").description(
"JWT token: Bearer dXNlcjpzZWNyZXQ=")),
requestParameters(
parameterWithName("page").description("The page to retrieve"),
parameterWithName("pageSize").description("Entries per page"),
parameterWithName("orderBy").description("Entries orderBy"),
parameterWithName("direction").description("Entries orderBy direction"),
parameterWithName("searchName").description("filter by column name"),
parameterWithName("searchValue").description("filter by column name's value"),
parameterWithName("nameLike").description("use name like or not")
)
// responseHeaders(
// headerWithName("X-RateLimit-Reset").description(
// "Time at which the rate limit period will reset"))
));
}