spring-boot並非全新的技術棧,而是整合了spring的不少組件,而且以約定優先的原則進行組合。使用boot咱們不須要對冗雜的配置文件進行管理,主須要用它的註解即可啓用大部分web開發中所須要的功能。本篇就是基於boot來配置jpa和靜態文件訪問,進行web應用的開發。html
最原始的jsp頁面在springboot中已經不在默認支持,spring-boot默認使用thymeleaf最爲模板。固然咱們也可使用freemark或者velocity等其餘後端模板。可是按照先後端分離的良好設計,咱們最好採用靜態頁面做爲前端模板,這樣先後端徹底分離,把數據處理邏輯寫在程序並提供接口供前端調用。這樣的設計更加靈活和清晰。前端
咱們將討論項目的結構、application配置文件、靜態頁面處理、自定義filter,listener,servlet以及攔截器的使用。最後集中討論jpa的配置和操做以及如何進行單元測試和打包部署。java
項目使用maven進行依賴管理和構建,總體結構以下圖所示:
咱們的HTML頁面和資源文件都在resources/static下,打成jar包的時候static目錄位於/BOOT-INF/classes/。node
咱們須要依賴下面這些包:
mysql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
複製代碼 |
<?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>
<groupId>gxf.dev</groupId>
<artifactId>topology</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.10.RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
<repositories>
<repository>
<id>nexus-aliyun</id>
<name>Nexus aliyun</name>
<layout>default</layout>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>gxf.dev.topology.Application</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
複製代碼 |
spring-boot-starter-parent使咱們項目的父pom。
spring-boot-starter-web提供嵌入式tomcat容器,從而使項目能夠經過打成jar包的方式直接運行。
spring-boot-starter-data-jpa引入了jpa的支持。
spring-boot-test和junit配合作單元測試。
mysql-connector-java和HikariCP作數據庫的鏈接池的操做。
spring-boot-maven-plugin插件能把項目和依賴的jar包以及資源文件和頁面一塊兒打成一個可運行的jar(運行在內嵌的tomcat)git
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
複製代碼 |
package gxf.dev.topology;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@EnableAutoConfiguration
@ServletComponentScan
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
複製代碼 |
這裏ServletComponentScan註解是啓用servlet3的servler和filter以及listener的支持,下面會提到該用法。要注意的是:不能引入@EnableWebMvc註解,不然須要從新配置視圖和資源文件映射。這樣就不符合咱們的先後端分離的初衷了。github
spring-boot默認會去classpath下面的/static/,/public/ ,/resources/目錄去讀取靜態資源。所以按照約定優先的原則,咱們直接把咱們應用的頁面和資源文件直接放在/static下面,以下圖所示:
這樣咱們訪問系統主頁就會自動加載index.html,並且它所引用的資源文件也會在static/下開始加載。web
咱們在application配置文件中設置各類參數,它能夠是傳統的properties文件也可使用yml來逐級配置。本文采用的第二種方式yml,若是不懂能夠參考:baike.baidu.com/item/YAML/1…。其內容以下:
spring
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
複製代碼 |
server:
port: 8080
context-path: /topology
session:
timeout: 30
tomcat:
uri-encoding: utf-8
logging:
level:
root: info
gxf.dev.topology: debug
#當配置了loggin.path屬性時,將在該路徑下生成spring.log文件,即:此時使用默認的日誌文件名spring.log
#當配置了loggin.file屬性時,將在指定路徑下生成指定名稱的日誌文件。默認爲項目相對路徑,能夠爲logging.file指定絕對路徑。
#path: /home/gongxufan/logs
file: topology.log
spring:
jpa:
show-sql: true
open-in-view: false
hibernate:
naming:
#配置ddl建表字段和實體字段一致
physical-strategy: gxf.dev.topology.config.RealNamingStrategyImpl
ddl-auto: update
properties:
hibernate:
format_sql: true
show_sql: true
dialect: org.hibernate.dialect.MySQL5Dialect
datasource:
url: jdbc:mysql://localhost:3306/topology
driver-class-name: com.mysql.jdbc.Driver
username: root
password: qwe
hikari:
cachePrepStmts: true
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
useServerPrepStmts: true
複製代碼 |
使用idea開發工具在編輯器會有自動變量提示,這樣很是方便進行參數的選擇和查閱。sql
server節點能夠配置容器的不少參數,好比:端口,訪問路徑、還有tomcat自己的一些參數。這裏設置了session的超時以及編碼等。
日誌級別能夠定義到具體的哪一個包路徑,日誌文件的配置要注意:path和file配置一個就行,file默認會在程序工做目錄下生成,也能夠置頂絕對路徑進行指定。
這裏使用號稱性能最牛逼的鏈接池hikaricp,具體配置能夠參閱其官網:brettwooldridge.github.io/HikariCP/
這裏主要注意下strategy的配置,關係到自動建表時的字段命名規則。默認會生成帶_劃線分割entity的字段名(駱駝峯式)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
複製代碼 |
package gxf.dev.topology.config;
/**
* ddl-auto選項開啓的時候生成表的字段命名策略,默認會按照駱駝峯式風格用_隔開每一個單詞
* 這個類能夠保證entity定義的字段名和數據表的字段一致
* @auth gongxufan
* @Date 2016/8/3
**/
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import java.io.Serializable;
public class RealNamingStrategyImpl extends org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy implements Serializable {
public static final PhysicalNamingStrategyStandardImpl INSTANCE = new PhysicalNamingStrategyStandardImpl();
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
return new Identifier(name.getText(), name.isQuoted());
}
@Override
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment context) {
return new Identifier(name.getText(), name.isQuoted());
}
}
複製代碼 |
1) 最新的spring-boot引入新的註解ServletComponentScan,使用它能夠方便的配置Servlet3+的web組件。主要有下面這三個註解:
1
2
3
複製代碼 |
@WebServlet
@WebFilter
@WebListener
複製代碼 |
只要把這些註解標記組件便可完成註冊。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
複製代碼 |
package gxf.dev.topology.filter;
import org.springframework.core.annotation.Order;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* author:gongxufan
* date:11/14/17
**/
@Order(1)
@WebFilter(filterName = "loginFilter", urlPatterns = "/login")
public class LoginFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("login rquest");
chain.doFilter(request,response);
}
@Override
public void destroy() {
}
}
複製代碼 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
複製代碼 |
package gxf.dev.topology.filter;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* 自定義listener
* Created by gongxufan on 2016/7/5.
*/
@WebListener
public class SessionListener implements HttpSessionListener,HttpSessionAttributeListener {
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
System.out.println("init");
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
System.out.println("destroy");
}
@Override
public void attributeAdded(HttpSessionBindingEvent se) {
System.out.println(se.getName() + ":" + se.getValue());
}
@Override
public void attributeRemoved(HttpSessionBindingEvent se) {
}
@Override
public void attributeReplaced(HttpSessionBindingEvent se) {
}
}
複製代碼 |
2) 攔截器的使用
攔截器不是Servlet規範的標準組件,它跟上面的三個組件不在一個處理鏈上。攔截器是spring使用AOP實現的,對controller執行先後能夠進行干預,直接結束請求處理。並且攔截器只能對流經dispatcherServlet處理的請求才生效,靜態資源就不會被攔截。
下面頂一個攔截器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
複製代碼 |
package gxf.dev.topology.filter;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* author:gongxufan
* date:11/14/17
**/
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
System.out.println("LoginInterceptor.preHandle()在請求處理以前進行調用(Controller方法調用以前)");
// 只有返回true纔會繼續向下執行,返回false取消當前請求
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("LoginInterceptor.postHandle()請求處理以後進行調用,可是在視圖被渲染以前(Controller方法調用以後)");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("LoginInterceptor.afterCompletion()在整個請求結束以後被調用,也就是在DispatcherServlet 渲染了對應的視圖以後執行(主要是用於進行資源清理工做)");
}
}
複製代碼 |
要想它生效則須要加入攔截器棧:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
複製代碼 |
package gxf.dev.topology.config;
import gxf.dev.topology.filter.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
/**
* author:gongxufan
* date:11/14/17
**/
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
//在這能夠配置controller的訪問路徑
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**");
super.addInterceptors(registry);
}
}
複製代碼 |
spring-boot已經集成了JPA的Repository封裝,基於註解的事務處理等,咱們只要按照常規的JPA使用方法便可。以Node表的操做爲例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
複製代碼 |
package gxf.dev.topology.entity;
import com.fasterxml.jackson.annotation.JsonInclude;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
/**
* Created by gongxufan on 2014/11/20.
*/
@Entity
@Table(name = "node")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Node implements Serializable {
@Id
private String id;
private String elementType;
private String x;
private String y;
private String width;
private String height;
private String alpha;
private String rotate;
private String scaleX;
private String scaleY;
private String strokeColor;
private String fillColor;
private String shadowColor;
private String shadowOffsetX;
private String shadowOffsetY;
private String zIndex;
private String text;
private String font;
private String fontColor;
private String textPosition;
private String textOffsetX;
private String textOffsetY;
private String borderRadius;
private String deviceId;
private String dataType;
private String borderColor;
private String offsetGap;
private String childNodes;
private String nodeImage;
private String templateId;
private String deviceA;
private String deviceZ;
private String lineType;
private String direction;
private String vmInstanceId;
private String displayName;
private String vmid;
private String topoLevel;
private String parentLevel;
private Setring nextLevel;
//getter&setter
}
複製代碼 |
JsonInclude註解用於返回JOSN字符串是忽略爲空的字段。
編寫repository接口
1
2
3
4
5
6
7
複製代碼 |
package gxf.dev.topology.repository;
import gxf.dev.topology.entity.Node;
import org.springframework.data.repository.PagingAndSortingRepository;
public interface NodeRepository extends PagingAndSortingRepository<Node, String> {
}
複製代碼 |
編寫Service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
複製代碼 |
package gxf.dev.topology.service;
import gxf.dev.topology.entity.Node;
import gxf.dev.topology.repository.NodeRepository;
import gxf.dev.topology.repository.SceneRepository;
import gxf.dev.topology.repository.StageRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
/**
* dao操做
* author:gongxufan
* date:11/13/17
**/
@Component
public class TopologyService {
@Autowired
private NodeRepository nodeRepository;
@Autowired
private SceneRepository sceneRepository;
@Autowired
private StageRepository stageRepository;
@Transactional
public Node saveNode(Node node) {
return nodeRepository.save(node);
}
public Iterable<Node> getAll() {
return nodeRepository.findAll();
}
}
複製代碼 |
單元測試使用spring-boot-test和junit進行,須要用到下面的幾個註解:
1
2
複製代碼 |
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
複製代碼 |
測試代碼以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
複製代碼 |
import gxf.dev.topology.Application;
import gxf.dev.topology.entity.Node;
import gxf.dev.topology.repository.CustomSqlDao;
import gxf.dev.topology.service.TopologyService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* author:gongxufan
* date:11/13/17
**/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class ServiceTest {
@Autowired
private TopologyService topologyService;
@Autowired
private CustomSqlDao customSqlDao;
@Test
public void testNode() {
Node node = new Node();
node.setId("node:2");
node.setDisplayName("test1");
topologyService.saveNode(node);
}
@Test
public void testNative(){
System.out.println(customSqlDao.querySqlObjects("select * from node"));
System.out.println(customSqlDao.getMaxColumn("id","node"));
}
}
複製代碼 |
使用JPA進行單表操做確實很方便,可是對於多表鏈接的複雜查詢可能不太方便。通常有兩種方式彌補這個不足:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
複製代碼 |
package gxf.dev.topology.repository;
import com.mysql.jdbc.StringUtils;
import org.hibernate.SQLQuery;
import org.hibernate.criterion.CriteriaSpecification;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 支持自定義SQL查詢
* Created by gongxufan on 2016/3/17.
*/
@Component
public class CustomSqlDao {
@Autowired
private EntityManagerFactory entityManagerFactory;
public int getMaxColumn(final String filedName, final String tableName) {
String sql = "select nvl(max(" + filedName + "), 0) as max_num from " + tableName;
Map map = entityManagerFactory.getProperties();
String dialect = (String) map.get("hibernate.dialect");
//determine which database use
if(!StringUtils.isNullOrEmpty(dialect)){
if(dialect.contains("MySQL")){
sql = "select ifnull(max(" + filedName + "), 0) as max_num from " + tableName;
}
if(dialect.contains("Oracle")){
sql = "select nvl(max(" + filedName + "), 0) as max_num from " + tableName;
}
}
int maxID = 0;
List<Map<String, Object>> list = this.querySqlObjects(sql);
if (list.size() > 0) {
Object maxNum = list.get(0).get("max_num");
if(maxNum instanceof Number)
maxID = ((Number)maxNum).intValue();
if(maxNum instanceof String)
maxID = Integer.valueOf((String)maxNum);
}
return maxID + 1;
}
public List<Map<String, Object>> querySqlObjects(String sql, Integer currentPage, Integer rowsInPage) {
return this.querySqlObjects(sql, null, currentPage, rowsInPage);
}
public List<Map<String, Object>> querySqlObjects(String sql) {
return this.querySqlObjects(sql, null, null, null);
}
public List<Map<String, Object>> querySqlObjects(String sql, Map params) {
return this.querySqlObjects(sql, params, null, null);
}
@SuppressWarnings("unchecked")
public List<Map<String, Object>> querySqlObjects(String sql, Object params, Integer currentPage, Integer rowsInPage) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
Query qry = entityManager.createNativeQuery(sql);
SQLQuery s = qry.unwrap(SQLQuery.class);
//設置參數
if (params != null) {
if (params instanceof List) {
List<Object> paramList = (List<Object>) params;
for (int i = 0, size = paramList.size(); i < size; i++) {
qry.setParameter(i + 1, paramList.get(i));
}
} else if (params instanceof Map) {
Map<String, Object> paramMap = (Map<String, Object>) params;
Object o = null;
for (String key : paramMap.keySet()) {
o = paramMap.get(key);
if (o != null)
qry.setParameter(key, o);
}
}
}
if (currentPage != null && rowsInPage != null) {//判斷是否有分頁
// 起始對象位置
qry.setFirstResult(rowsInPage * (currentPage - 1));
// 查詢對象個數
qry.setMaxResults(rowsInPage);
}
s.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);
List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
try {
List list = qry.getResultList();
resultList = s.list();
} catch (Exception e) {
e.printStackTrace();
} finally {
entityManager.close();
}
return resultList;
}
public int getCount(String sql) {
String sqlCount = "select count(0) as count_num from " + sql;
List<Map<String, Object>> list = this.querySqlObjects(sqlCount);
if (list.size() > 0) {
int countNum = ((BigDecimal) list.get(0).get("COUNT_NUM")).intValue();
return countNum;
} else {
return 0;
}
}
/**
* 處理sql語句
*
* @param _strSql
* @return
*/
public String toSql(String _strSql) {
String strNewSql = _strSql;
if (strNewSql != null) {
strNewSql = regReplace("'", "''", strNewSql);
} else {
strNewSql = "";
}
return strNewSql;
}
private String regReplace(String strFind, String strReplacement, String strOld) {
String strNew = strOld;
Pattern p = null;
Matcher m = null;
try {
p = Pattern.compile(strFind);
m = p.matcher(strOld);
strNew = m.replaceAll(strReplacement);
} catch (Exception e) {
}
return strNew;
}
/**
* 根據hql語句查詢數據
*
* @param hql
* @return
*/
@SuppressWarnings("rawtypes")
public List queryForList(String hql, List<Object> params) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
Query query = entityManager.createQuery(hql);
List list = null;
try {
if (params != null && !params.isEmpty()) {
for (int i = 0, size = params.size(); i < size; i++) {
query.setParameter(i + 1, params.get(i));
}
}
list = query.getResultList();
} catch (Exception e) {
e.printStackTrace();
} finally {
entityManager.close();
}
return list;
}
@SuppressWarnings("rawtypes")
public List queryByMapParams(String hql, Map<String, Object> params, Integer currentPage, Integer pageSize) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
Query query = entityManager.createQuery(hql);
List list = null;
try {
if (params != null && !params.isEmpty()) {
for (Map.Entry<String, Object> entry : params.entrySet()) {
query.setParameter(entry.getKey(), entry.getValue());
}
}
if (currentPage != null && pageSize != null) {
query.setFirstResult((currentPage - 1) * pageSize);
query.setMaxResults(pageSize);
}
list = query.getResultList();
} catch (Exception e) {
e.printStackTrace();
} finally {
entityManager.close();
}
return list;
}
@SuppressWarnings("rawtypes")
public List queryByMapParams(String hql, Map<String, Object> params) {
return queryByMapParams(hql, params, null, null);
}
@SuppressWarnings("rawtypes")
public List queryForList(String hql) {
return queryForList(hql, null);
}
/**
* 查詢總數
*
* @param hql
* @param params
* @return
*/
public Long queryCount(String hql, Map<String, Object> params) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
Query query = entityManager.createQuery(hql);
Long count = null;
try {
if (params != null && !params.isEmpty()) {
for (Map.Entry<String, Object> entry : params.entrySet()) {
query.setParameter(entry.getKey(), entry.getValue());
}
}
count = (Long) query.getSingleResult();
} catch (Exception e) {
e.printStackTrace();
} finally {
entityManager.close();
}
return count;
}
/**
* 查詢總數
*
* @param sql
* @param params
* @return
*/
public Integer queryCountBySql(String sql, Map<String, Object> params) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
Integer count = null;
try {
Query query = entityManager.createNativeQuery(sql);
if (params != null && !params.isEmpty()) {
for (Map.Entry<String, Object> entry : params.entrySet()) {
query.setParameter(entry.getKey(), entry.getValue());
}
}
Object obj = query.getSingleResult();
if (obj instanceof BigDecimal) {
count = ((BigDecimal) obj).intValue();
} else {
count = (Integer) obj;
}
} finally {
if (entityManager != null) {
entityManager.close();
}
}
return count;
}
/**
* select count(*) from table
*
* @param sql
* @param params
* @return
*/
public int executeSql(String sql, List<Object> params) {
EntityManager entityManager = entityManagerFactory.createEntityManager();
try {
Query query = entityManager.createNativeQuery(sql);
if (params != null && !params.isEmpty()) {
for (int i = 0, size = params.size(); i < size; i++) {
query.setParameter(i + 1, params.get(i));
}
}
return query.executeUpdate();
} finally {
if (entityManager != null) {
entityManager.close();
}
}
}
}
複製代碼 |
咱們在service層注入,而後就能夠根據輸入條件拼接好sql或者hql來進行各類操做。這種方式靈活並且也不須要手動寫分頁代碼,使用hibernate封裝好的機制便可。
使用boot能夠快速搭建一個先後端開發的骨架,裏面有不少自動的配置和約定。雖然boot不是新的一個技術棧,可是它要求咱們對各個組件都要比較熟悉,否則對它的運行機制和約定配置會感到很困惑。而使用JPA進行數據庫操做也是利弊參半,須要本身權衡。