【SpringBoot Demo】MySQL + JPA + Hibernate + Springboot + Maven Demo
主要包含:springboot+jpa+hibernate+mysql+lombok
(两年前写过一个,现在重新记录一个)
1. 目录结构:
2. pom 文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4 <modelVersion>4.0.0</modelVersion> 5 <groupId>com.test</groupId> 6 <artifactId>demo</artifactId> 7 <version>0.0.1-SNAPSHOT</version> 8 <name>demo</name> 9 <description>demo for Spring Boot</description> 10 <properties> 11 <java.version>1.8</java.version> 12 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 13 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> 14 <spring-boot.version>2.6.13</spring-boot.version> 15 </properties> 16 <dependencies> 17 <dependency> 18 <groupId>org.springframework.boot</groupId> 19 <artifactId>spring-boot-starter-web</artifactId> 20 </dependency> 21 <dependency> 22 <groupId>org.springframework.boot</groupId> 23 <artifactId>spring-boot-starter-data-jpa</artifactId> 24 </dependency> 25 <dependency> 26 <groupId>com.querydsl</groupId> 27 <artifactId>querydsl-jpa</artifactId> 28 <version>4.1.4</version> 29 </dependency> 30 <dependency> 31 <groupId>com.querydsl</groupId> 32 <artifactId>querydsl-apt</artifactId> 33 <version>4.1.4</version> 34 </dependency> 35 <dependency> 36 <groupId>com.alibaba</groupId> 37 <artifactId>fastjson</artifactId> 38 <version>2.0.32</version> 39 </dependency> 40 <dependency> 41 <groupId>commons-lang</groupId> 42 <artifactId>commons-lang</artifactId> 43 <version>2.6</version> 44 </dependency> 45 <dependency> 46 <groupId>org.apache.httpcomponents</groupId> 47 <artifactId>httpclient</artifactId> 48 <version>4.5.13</version> 49 </dependency> 50 <dependency> 51 <groupId>mysql</groupId> 52 <artifactId>mysql-connector-java</artifactId> 53 <version>8.0.19</version> 54 </dependency> 55 <dependency> 56 <groupId>org.projectlombok</groupId> 57 <artifactId>lombok</artifactId> 58 <optional>true</optional> 59 </dependency> 60 <dependency> 61 <groupId>org.springframework.boot</groupId> 62 <artifactId>spring-boot-starter-test</artifactId> 63 <scope>test</scope> 64 </dependency> 65 </dependencies> 66 <dependencyManagement> 67 <dependencies> 68 <dependency> 69 <groupId>org.springframework.boot</groupId> 70 <artifactId>spring-boot-dependencies</artifactId> 71 <version>${spring-boot.version}</version> 72 <type>pom</type> 73 <scope>import</scope> 74 </dependency> 75 </dependencies> 76 </dependencyManagement> 77 78 <build> 79 <plugins> 80 <plugin> 81 <groupId>org.apache.maven.plugins</groupId> 82 <artifactId>maven-compiler-plugin</artifactId> 83 <version>3.8.1</version> 84 <configuration> 85 <source>1.8</source> 86 <target>1.8</target> 87 <encoding>UTF-8</encoding> 88 </configuration> 89 </plugin> 90 <plugin> 91 <groupId>org.springframework.boot</groupId> 92 <artifactId>spring-boot-maven-plugin</artifactId> 93 <version>${spring-boot.version}</version> 94 <configuration> 95 <includeSystemScope>true</includeSystemScope> 96 <mainClass>com.tst.demo.demoApplication</mainClass> 97 </configuration> 98 <executions> 99 <execution> 100 <id>repackage</id> 101 <goals> 102 <goal>repackage</goal> 103 </goals> 104 </execution> 105 </executions> 106 </plugin> 107 </plugins> 108 </build> 109 <!-- 配置阿里云仓库 --> 110 <repositories> 111 <repository> 112 <id>dzh-public</id> 113 <name>dzh maven</name> 114 <url>https://maven.aliyun.com/repository/public/</url> 115 <releases> 116 <enabled>true</enabled> 117 </releases> 118 </repository> 119 </repositories> 120 121 <pluginRepositories> 122 <pluginRepository> 123 <id>dzh-public-plugin</id> 124 <name>dzh nexus plugin</name> 125 <url>https://maven.aliyun.com/repository/public/</url> 126 <releases> 127 <enabled>true</enabled> 128 </releases> 129 <snapshots> 130 <enabled>false</enabled> 131 </snapshots> 132 </pluginRepository> 133 </pluginRepositories> 134 135 </project>
3. 启动类
package com.test.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
4. 配置文件
application.yml
server: websocket: max-text-message-buffer-size: 9MB max-binary-message-buffer-size: 9MB application: target-url: https://xxx # 全局配置逻辑配置 spring: resources: static-locations: file:D:\\\\demo\\static\\ #对应服务器内映射的实际路径 mvc: static-path-pattern: /static/** #对应服务通过url访问静态文件夹时的前缀 servlet: multipart: enabled: true max-file-size: 100MB max-request-size: 100MB jpa: database: MYSQL profiles: active: dev
application-dev.yml
server: port: 8081 # ssl: # 证书自行配置 # key-store: classpath:keystore.p12 # key-store-password: 123456 # key-password: 123456 # key-store-type: PKCS12 # key-alias: tomcat spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: xxx
application-prod.yml与上述基本一致,部分配置自行调整
5. 配置类
package com.test.demo.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; @Data @Configuration @ConfigurationProperties(prefix = "application", ignoreUnknownFields = false) public class ApplicationProperties { private String targetUrl; }
静态文件夹
package com.test.demo.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration public class WebMvcConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { //将所有/static/** 访问都映射到classpath:/static/ 目录下 registry.addResourceHandler("/static/**").addResourceLocations("file:D:\\demo\\static\\"); } @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // .allowedOrigins("*") .allowedOriginPatterns("*") .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE") .maxAge(3600) .allowCredentials(true); } }
RestTemplate全局配置(忽略证书验证)
package com.test.demo.config; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContexts; import org.apache.http.ssl.TrustStrategy; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.web.client.RestTemplate; import javax.net.ssl.SSLContext; import java.nio.charset.Charset; import java.util.List; @Configuration public class RestTemplateConfig { @Bean("restTemplate") public RestTemplate RestTemplate() { HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(); httpRequestFactory.setConnectionRequestTimeout(30000); httpRequestFactory.setConnectTimeout(30000); httpRequestFactory.setReadTimeout(30000); return new RestTemplate(httpRequestFactory); } /** * 用于https请求,忽略认证 * @return unSSLRestTemplate */ @Bean("unSSLRestTemplate") public RestTemplate restTemplateHttps() { RestTemplate restTemplate = null; try { TrustStrategy acceptingTrustStrategy = (chain, authType) -> true; SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); HttpClientBuilder clientBuilder = HttpClients.custom(); CloseableHttpClient httpClient = clientBuilder.setSSLSocketFactory(sslsf).build(); HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(); httpRequestFactory.setConnectionRequestTimeout(30000); httpRequestFactory.setConnectTimeout(30000); httpRequestFactory.setReadTimeout(30000); httpRequestFactory.setHttpClient(httpClient); restTemplate = new RestTemplate(httpRequestFactory); //解决乱码 List<HttpMessageConverter<?>> httpMessageConverters = restTemplate.getMessageConverters(); httpMessageConverters.stream().forEach(httpMessageConverter ->{ if(httpMessageConverter instanceof StringHttpMessageConverter){ StringHttpMessageConverter messageConverter = (StringHttpMessageConverter)httpMessageConverter; messageConverter.setDefaultCharset(Charset.forName("UTF-8")); } }); } catch (Exception e) { e.printStackTrace(); } return restTemplate; } }
6. 实体类
示例
package com.test.demo.domain; import lombok.Data; import javax.persistence.*; import java.time.Instant; @Data @Entity @Table(name = "xxx_log") public class XXXLog { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO, generator = "default") @TableGenerator(name = "default") @SequenceGenerator(name = "default", sequenceName = "HIBERNATE_SEQUENCE") private Long id; private int status_code; private Instant create_time = Instant.now(); private String event_type; private String event_desc; private String target_url; }
7. repository
示例
package com.test.demo.repository; import com.test.demo.domain.XXXLog; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; public interface XXXLogRepository extends JpaRepository<XXXLog, String> { List<XXXLog> findAll(); }
8. service
示例
package com.test.demo.service; import com.test.demo.domain.XXXLog; import com.test.demo.repository.XXXLogRepository; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.servlet.http.HttpServletRequest; import java.util.UUID; @Service @Slf4j public class LogService { @Autowired private XXXLogRepository xxxLogRepository; public String save(HttpServletRequest request) { String eventUid = String.valueOf(UUID.randomUUID()); log.info("记录开始时间 uid : " + eventUid + "事件ID codeId: " + eventUid + " start"); XXXLog xxxLog = new XXXLog(); xxxLog.setTarget_url("xxx"); xxxLog.setEvent_desc("xxx"); xxxLogRepository.save(xxxLog); log.info("记录停止时间 uid : " + eventUid + "事件ID codeId: " + eventUid + " start"); return eventUid; } }
9. 测试接口(get & post)
package com.test.demo.demos.web; import com.test.demo.bean.ApiResult; import com.test.demo.bean.XXXData; import com.test.demo.service.LogService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.io.IOException; @Slf4j @RestController @RequestMapping("evn") public class EventDemoController { @Autowired private LogService logService; @GetMapping("/test") @ResponseBody public ApiResult getMeetingInfo(String xx) throws IOException { log.info("XX: start"); // xx log.info("XX: end"); return ApiResult.ok("ok"); } @PostMapping("/log") @ResponseBody public ApiResult login(@RequestBody XXXData data, HttpServletRequest request) { log.info("visit save -----------start"); String eventUid = logService.save(request); log.info("visit save -----------end"); return ApiResult.ok(eventUid); } }
10. 测试Bean
ApiResult
package com.test.demo.bean; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.Data; import java.io.Serializable; import java.time.LocalDateTime; @Data @JsonInclude(JsonInclude.Include.NON_NULL) public class ApiResult implements Serializable { private int code; private String msg; private Object data; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime timestamp; public static <T> ApiResult ok() { ApiResult apiResult = new ApiResult(); apiResult.setCode(ApiStatus.OK.getCode()); apiResult.setMsg(ApiStatus.OK.getMsg()); apiResult.setData(null); apiResult.setTimestamp(LocalDateTime.now()); return apiResult; } public static <T> ApiResult ok(String msg) { ApiResult apiResult = new ApiResult(); apiResult.setCode(ApiStatus.OK.getCode()); apiResult.setMsg(msg); apiResult.setData(null); apiResult.setTimestamp(LocalDateTime.now()); return apiResult; } public static <T> ApiResult ok(int code, T data) { ApiResult apiResult = new ApiResult(); apiResult.setCode(code); apiResult.setMsg(ApiStatus.OK.getMsg()); apiResult.setData(data); apiResult.setTimestamp(LocalDateTime.now()); return apiResult; } public static <T> ApiResult ok(T data) { ApiResult apiResult = new ApiResult(); apiResult.setCode(ApiStatus.OK.getCode()); apiResult.setMsg(ApiStatus.OK.getMsg()); apiResult.setData(data); apiResult.setTimestamp(LocalDateTime.now()); return apiResult; } public static <T> ApiResult ok(String msg, Object data) { ApiResult apiResult = new ApiResult(); apiResult.setCode(ApiStatus.OK.getCode()); apiResult.setMsg(msg); apiResult.setData(data); apiResult.setTimestamp(LocalDateTime.now()); return apiResult; } public static <T> ApiResult fail() { ApiResult apiResult = new ApiResult(); apiResult.setCode(ApiStatus.FAIL.getCode()); apiResult.setMsg(ApiStatus.FAIL.getMsg()); apiResult.setData(null); apiResult.setTimestamp(LocalDateTime.now()); return apiResult; } public static <T> ApiResult fail(String failMsg) { ApiResult apiResult = new ApiResult(); apiResult.setCode(ApiStatus.FAIL.getCode()); apiResult.setMsg(failMsg); apiResult.setData(null); apiResult.setTimestamp(LocalDateTime.now()); return apiResult; } public static <T> ApiResult fail(int code, String failMsg) { ApiResult apiResult = new ApiResult(); apiResult.setCode(code); apiResult.setMsg(failMsg); apiResult.setData(null); apiResult.setTimestamp(LocalDateTime.now()); return apiResult; } public static <T> ApiResult fail(int code, String failMsg, T data) { ApiResult apiResult = new ApiResult(); apiResult.setCode(code); apiResult.setMsg(failMsg); apiResult.setData(data); apiResult.setTimestamp(LocalDateTime.now()); return apiResult; } public static <T> ApiResult fail(String failMsg, T data) { ApiResult apiResult = new ApiResult(); apiResult.setCode(ApiStatus.FAIL.getCode()); apiResult.setMsg(failMsg); apiResult.setData(data); apiResult.setTimestamp(LocalDateTime.now()); return apiResult; } public static <T> ApiResult error() { ApiResult apiResult = new ApiResult(); apiResult.setCode(ApiStatus.ERROR.getCode()); apiResult.setMsg(ApiStatus.ERROR.getMsg()); apiResult.setData(null); apiResult.setTimestamp(LocalDateTime.now()); return apiResult; } public static <T> ApiResult error(String exMsg) { ApiResult apiResult = new ApiResult(); apiResult.setCode(ApiStatus.ERROR.getCode()); apiResult.setMsg(exMsg); apiResult.setData(null); apiResult.setTimestamp(LocalDateTime.now()); return apiResult; } public static <T> ApiResult error(String exMsg, T data) { ApiResult apiResult = new ApiResult(); apiResult.setCode(ApiStatus.ERROR.getCode()); apiResult.setMsg(exMsg); apiResult.setData(data); apiResult.setTimestamp(LocalDateTime.now()); return apiResult; } public static <T> ApiResult instance(ApiStatus apiStatus) { ApiResult apiResult = new ApiResult(); apiResult.setCode(apiStatus.getCode()); apiResult.setMsg(apiStatus.getMsg()); apiResult.setData(null); apiResult.setTimestamp(LocalDateTime.now()); return apiResult; } public boolean isFail() { return this.code != ApiStatus.OK.getCode(); } public boolean isSuccess() { return this.code == ApiStatus.OK.getCode(); } }
ApiStatus
package com.test.demo.bean; import org.springframework.http.HttpStatus; public enum ApiStatus { OK(200, "请求成功"), FAIL(400, "请求失败"), UNAUTHORIZED(HttpStatus.UNAUTHORIZED.value(), "非法访问"), FORBIDDEN(HttpStatus.FORBIDDEN.value(), "无权访问"), NOT_FOUND(HttpStatus.NOT_FOUND.value(), "请求资源不存在"), ERROR(HttpStatus.INTERNAL_SERVER_ERROR.value(), "服务内部异常"); private final int code; private final String msg; ApiStatus(int code, String msg) { this.code = code; this.msg = msg; } public int getCode() { return code; } public String getMsg() { return msg; } }
XXXData
package com.test.demo.bean; import lombok.Data; @Data public class XXXData { private String codeId; private String target; }
11. 数据库SQL
CREATE DATABASE IF NOT EXISTS `demo` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */; USE `demo`; DROP TABLE IF EXISTS `c_sys_conf`; CREATE TABLE `xxx_log` ( `id` decimal(38,0) NOT NULL COMMENT '主键', `status_code` int DEFAULT NULL COMMENT '状态码', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `event_type` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '操作类型', `event_desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '操作描述', `target_url` text CHARACTER SET utf8 COLLATE utf8_general_ci COMMENT '目的地址', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='测试的日志记录表'; DROP TABLE IF EXISTS `hibernate_sequence`; CREATE TABLE `hibernate_sequence` ( `next_val` bigint DEFAULT NULL, `sequence_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, PRIMARY KEY (`sequence_name`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; LOCK TABLES `hibernate_sequence` WRITE; INSERT INTO `hibernate_sequence` VALUES (1,'default'); UNLOCK TABLES;
12 .gitignore
HELP.md target/ !.mvn/wrapper/maven-wrapper.jar !**/src/main/**/target/ !**/src/test/**/target/ ### STS ### .apt_generated .classpath .factorypath .project .settings .springBeans .sts4-cache ### IntelliJ IDEA ### .idea *.iws *.iml *.ipr ### NetBeans ### /nbproject/private/ /nbbuild/ /dist/ /nbdist/ /.nb-gradle/ build/ !**/src/main/**/build/ !**/src/test/**/build/ ### VS Code ### .vscode/