舊專案必學技術整理 - Spring MVC & Spring Data

Posted by Tim Lin on 2018-12-01

後端程式說明

專案結構說明

brt-entity 下

放 ept entity, 其他都是吃 m2 下的 jar 檔的 entity

brt-netterm-applet 下

netterm 相關程式

brt-webapp 下

  • package gov.nta.brt.web.dto;
    • 會使用到的 dto 物件
  • package gov.nta.brt.web.rest;
    • rest api 程式入口點
  • package gov.nta.brt.web.controller;
    • 報表程式入口點

brt-service 下

  • package gov.nta.brt.dto;
    • 會使用到的 dto 物件
  • package gov.nta.brt.repository;
    • 各操作 db table 的 repository interface
  • package gov.nta.brt.repository.custom;
    • 各操作 db table 的 repository 客製化 interface
  • gov.nta.brt.repository.impl;
    • 客製化 interface 的實作
  • package gov.nta.brt.service;
    • 商業邏輯的程式
1
2
3
4
5
6
7
打 rest api 呼叫路徑:
1. xxxResouce.java 呼叫 xxxService.java 方法
2. xxxService.java 使用 xxxRepository.java 的方法去撈 db 資料

開報表 呼叫路徑:
1. xxxController.java 呼叫 xxxService.java 方法
2. xxxService.java 使用 xxxRepository.java 的方法去撈 db 資料

Spring annotation

xxxResource.java 或 xxxController.java 使用

@Slf4j
自動注入 log 來使用

@RequestMapping
https://www.baeldung.com/spring-requestmapping
簡單來說就是把 request 對應到 rest api method 上的 url

@Autowired
注入物件 讓 spring 控制物件的生命週期

@RequestBody
用在 post, put
the @RequestBody annotation maps the HttpRequest body to a transfer or domain object

@ResponseBody
The @ResponseBody annotation tells a controller that the object returned is automatically serialized into JSON and passed back into the HttpResponse object.

@Controller v.s @RestController
https://www.baeldung.com/spring-controller-vs-restcontroller

xxxService.java 使用

@Service
https://www.baeldung.com/spring-component-repository-service
We mark beans with @Service to indicate that it’s holding the business logic

Spring data

提供存取 DB 資料的框架

  • Why Spring Data?
    • 提供Code Gen. by Interface Method機制
    • 支援QueryDsl

程式架構說明

QueryDsl

1
2
3
BooleanExpression exp = customer.firstname.eq("Beta").and(customer.lastname.eq("Huang"));

Customer customer = repo.findOne(exp);

Code Gen. by Interface Method

1
2
3
4
5
6
7
public interface Brt910fdRepository extends EntityRepository<Brt910fd, Brt910fdId>, Brt910fdRepositoryCustom{

public List<Brt910fd> findByPasswdAndScode(String passwd, String scode);



}
  • By 之前可加 Distinct
  • By 之後為查詢的 where 條件
  • String 類別屬性可以標注 IgnoreCase
  • 可加 OrderBy

@Query

使用時機:當覺得根據規則寫出來的method name難以閱讀/理解時,以@Query替換執行的查詢語法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public interface Brt910fdRepository extends EntityRepository<Brt910fd, Brt910fdId>, Brt910fdRepositoryCustom{


@Query(value = "Select * from BRT910FD where passwd = :cardcode "
+ "and scode = :scode ", nativeQuery = true)
public List<Brt910fd> findByPasswd(@Param("cardcode") String cardcode,@Param("scode") String scode);

@Query(value = "Select * from BRT910FD where scode = :scode ", nativeQuery = true)
public List<Brt910fd> findOver3Month(@Param("scode") String scode);

@Query(value = "select * from BRT910FD where passwd =:desPass and scode = :scode ", nativeQuery = true)
public List<Brt910fd> findForcarcodeEnter(@Param("desPass") String desPass, @Param("scode") String scode);


}

repository 有提供基本操作與查詢的method

自己實做的方法

1
2
3
4
5
6
public interface Brt910fdRepositoryCustom {
public List<Sys306fa> checkSys306fa(String bchno, String workday, String scode);

public List<String> findFor952eRs1(String desPassWd);

}
1
2
3
public class Brt910fdRepositoryImpl implements Brt910fdRepositoryCustom {
...略
}

SqlExecutor

執行複雜的Native SQL

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
public class Brt910fdRepositoryImpl implements Brt910fdRepositoryCustom {

@Autowired
private SqlExecutor sqlExe;

@Override
public List<Sys306fa> checkSys306fa(String bchno, String workday, String scode) {
Map<String, Object> whereConsMap = new HashMap<String, Object>();
whereConsMap.put("scode", scode);

StringBuilder pdfName = new StringBuilder();
pdfName.append("(");
pdfName.append("'BRT202R_" + workday + "_" + bchno + ".pdf'");
pdfName.append(",'BRT243R_" + workday + "_" + bchno + ".pdf'");
pdfName.append(")");

StringBuilder sqlsb = new StringBuilder();
sqlsb.append("select * from sys306fa where scode = :scode and rpt_name in @{pdfName}");
sqlsb.append("");

String sql = sqlsb.toString();
sql = sql.replace("@{pdfName}", pdfName);

return sqlExe.queryForList(sql, whereConsMap, Sys306fa.class);
}

@Override
public List<String> findFor952eRs1(String desPassWd) {
String sql = " select '科長卡' as kind from Brt910fd where passwd = :desPassWd and scode = :scode "
+ " union all"
+ " select '科員卡' as kind from Brt910fa where passwd = :desPassWd and scode = :scode ";

Map<String, Object> whereConsMap = new HashMap<String, Object>();
NtaUser user = (NtaUser) UserHolder.getUser();
String scode = String.valueOf(user.getScode());

whereConsMap.put("desPassWd", desPassWd);
whereConsMap.put("scode", scode);

return sqlExe.queryForList(sql, whereConsMap, String.class);
}

}