透過反射操作共同方法
可以讓大家透過統一方式進行操作
- EntityOperationUtils 共用方法
- OperationObj 操作細項
- JpaEnum JPA的操作步驟
- PathConstant 靜態字串 放入實際物件的檔案結構
先準備細項
OperationObj
/
@param repositoryName 操作資料庫的物件名稱
@param method 操作資料庫的方法枚舉
@param parameters 操作資料庫物件方法要處理的紀錄資訊
@param entityName 紀錄名稱/@NoArgsConstructor @Data public class OperationObj { private String repositoryName; private Enum<?> method; private String params; private String entityName; private final Gson gson = new Gson(); public OperationObj(String repositoryName, Enum<?> method, Object params, String entityName) { this.repositoryName = repositoryName; this.method = method; this.params = gson.toJson(params); this.entityName = entityName; } }
JpaEnum
必須要為repository內有的方法(與jpa有關聯)
public enum JpaEnum {
saveAndFlush;
}
PathConstant
public class PathConstant {
public static final String BASE_PACKAGE = "com.testModule.life";
public static final String ENTITY_NAME = "com.testModule.life.entity."; // 尋找entity物件的完整路徑
public static final String REPOSITORY_NAME = "com.testModule.life.repository.main."; // 尋找repository物件的完整路徑
}
- 核心方法
EntityOperationUtils
*多executeJpa來決定要操作資料庫物件處理資料表資料(調整一下命名其實也適用於各類自行建立的物件方法)
*doJpaSth明定JPA方法來處理資校 其實MethodUtils.invokeMethod已經實作了
@Component
public class EntityOperationUtils {
@Autowired
ApplicationContext applicationContext;
private final Gson gson = new Gson();
public Boolean executeJpa(List<OperationObj> opObjList) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
for (OperationObj opObj :opObjList) {
String fullRepositoryPath=String.join("",PathConstant.REPOSITORY_MAIN_NAME,opObj.getRepositoryName());
Class<?> repositoryClass = Class.forName(fullRepositoryPath);
Object repository = applicationContext.getBean(repositoryClass);
Method method = repository.getClass().getMethod(opObj.getMethod().toString(),Object.class);
String fullEntityPath = String.join("",PathConstant.ENTITY_NAME + opObj.getEntityName());
Class<?> entityClass = Class.forName(fullEntityPath); MethodUtils.invokeMethod(repository,true,method.getName(),gson.fromJson(opObj.getParams(), entityClass));
}
return true;
}
public static Optional<?> doJpaSth(JpaRepository<?, ?> repository, String methodName, Object input, Class<?> argumentClassType) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
Gson gson = new Gson();
String inputStr = gson.toJson(input);
Object inputObj = new Gson().fromJson(inputStr, argumentClassType);
Method method = repository.getClass().getMethod(methodName, Object.class);
Object obj = method.invoke(repository,inputObj);
if (obj instanceof Optional) {
return (Optional<?>) obj;
}
return Optional.of(obj);
}
}
實際應用
@Test
void find() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
int pk = 1;
Optional<Country> res = countryRepository.findById(pk);
TypeReference<?> typeReference = new TypeReference<Country>() {
};
Class<?> classType = objectMapper.getTypeFactory().constructType(typeReference).getRawClass();
// 可以根據需求放入 list/map/collection...的型別
Optional<?> res2 = EntityOperationUtils.doJpaSth(countryRepository, "findById", pk, Integer.class);
Object res2Opt = MethodUtils.invokeMethod(countryRepository, "findById", pk);
if (res2Opt instanceof Optional<?>){
res2=(Optional<?>) res2Opt;
}
log.info(new Gson().toJson(res2.get()));
Country resO = (Country) res2.get();
Assertions.assertEquals(res.get().getId(), resO.getId());
}
片段程式碼
Country updated = this.findByCountryId(id);
if (Objects.isNull(updated)) {
return Collections.emptyMap();
}
Country origin = (Country) SerialUtil.cloneObject(updated);
updated.setDescription(description);
OperationObj updateOp = new OperationObj("CountryRepository", JpaEnum.saveAndFlush, updated, "Country");
// 異動實體表格
List<OperationObj> updateOpList = Collections.singletonList(updateOp);
entityOperationUtils.executeJpa(updateOpList);
看到這樣應用可能會覺得為什麼要多此一舉直接注入呼叫Jpa/自定義物件就好了
那我這邊列舉可能會用到的情境
- 當下沒有直接要對資料庫異動。例如:批次、審放、統一作法、觸發情境
這不是一個給新手的一個教學過程,也寫的不是很完整
希望大家多多包涵囉~
主要是給自己的一個紀錄,也分享給有需要的夥伴
這是一個心血來潮,產生的文章