From 83568bd9d5776862e348b7857a1aced9d2212a67 Mon Sep 17 00:00:00 2001 From: yunjy Date: Fri, 19 Aug 2022 10:37:36 +0900 Subject: [PATCH] =?UTF-8?q?=EC=8A=A4=ED=81=AC=EB=A6=BD=ED=8A=B8=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../eactive/httpmockserver/ApiController.java | 14 +- .../com/eactive/httpmockserver/ApiInfo.java | 11 ++ .../eactive/httpmockserver/script/Script.java | 6 + .../script/ScriptController.java | 118 ++++++++++++ .../httpmockserver/script/ScriptInfo.java | 67 +++++++ .../httpmockserver/script/ScriptInfoDao.java | 16 ++ .../script/ScriptInfoService.java | 27 +++ .../script/ScriptInfoServiceImpl.java | 87 +++++++++ .../httpmockserver/script/ScriptLoader.java | 82 +++++++++ src/main/resources/application.yml | 2 +- .../basecodes/BaseScript.java.template | 9 + .../resources/templates/fragment/sidebar.html | 16 ++ .../templates/page/add-edit-api.html | 13 ++ .../templates/page/add-edit-script-info.html | 169 ++++++++++++++++++ .../templates/page/list-script-info.html | 155 ++++++++++++++++ 15 files changed, 790 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/eactive/httpmockserver/script/Script.java create mode 100644 src/main/java/com/eactive/httpmockserver/script/ScriptController.java create mode 100644 src/main/java/com/eactive/httpmockserver/script/ScriptInfo.java create mode 100644 src/main/java/com/eactive/httpmockserver/script/ScriptInfoDao.java create mode 100644 src/main/java/com/eactive/httpmockserver/script/ScriptInfoService.java create mode 100644 src/main/java/com/eactive/httpmockserver/script/ScriptInfoServiceImpl.java create mode 100644 src/main/java/com/eactive/httpmockserver/script/ScriptLoader.java create mode 100644 src/main/resources/basecodes/BaseScript.java.template create mode 100644 src/main/resources/templates/page/add-edit-script-info.html create mode 100644 src/main/resources/templates/page/list-script-info.html diff --git a/src/main/java/com/eactive/httpmockserver/ApiController.java b/src/main/java/com/eactive/httpmockserver/ApiController.java index bed127f..7b9f33e 100644 --- a/src/main/java/com/eactive/httpmockserver/ApiController.java +++ b/src/main/java/com/eactive/httpmockserver/ApiController.java @@ -1,5 +1,6 @@ package com.eactive.httpmockserver; +import java.lang.reflect.InvocationTargetException; import java.util.Map; import java.util.Map.Entry; import java.util.Random; @@ -7,6 +8,8 @@ import java.util.Random; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import com.eactive.httpmockserver.script.Script; +import com.eactive.httpmockserver.script.ScriptLoader; import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.JsonPath; @@ -21,6 +24,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.server.ResponseStatusException; @@ -41,7 +45,7 @@ public class ApiController { //@RequestMapping(value = "/mock-api/**") @RequestMapping(value = "/{_:^(?!plugins|dist|favicon.ico).*$}/**") public ResponseEntity mockApi(HttpEntity httpEntity, HttpServletRequest request, - HttpServletResponse response) { + HttpServletResponse response) throws Exception { logger.info("=================================================="); logger.info("=================================================="); logger.info(request.getServletPath()); @@ -119,6 +123,14 @@ public class ApiController { } String responseStr = assignResponseBody(api); + + String scriptName = api.getScriptName(); + if(StringUtils.isNotBlank(scriptName)) { + Script script = ScriptLoader.getInstance().newScript(scriptName); + logger.info("Execute postProcess Script={}", scriptName); + + responseStr = script.postProcess(httpEntity.getBody(), responseStr); + } logger.info("ResponseBody={}", responseStr); return new ResponseEntity(responseStr, responseHeaders, responseStatusCode); diff --git a/src/main/java/com/eactive/httpmockserver/ApiInfo.java b/src/main/java/com/eactive/httpmockserver/ApiInfo.java index 36b8a4e..cb16d1f 100644 --- a/src/main/java/com/eactive/httpmockserver/ApiInfo.java +++ b/src/main/java/com/eactive/httpmockserver/ApiInfo.java @@ -43,6 +43,9 @@ public class ApiInfo implements Serializable { @Column(length = 10) private String method; + @Column(length = 500) + private String scriptName; + @Column(length = 50) private String responseContentType; @@ -181,6 +184,14 @@ public class ApiInfo implements Serializable { this.syntaxResponseBody2 = syntaxResponseBody2; } + public String getScriptName() { + return scriptName; + } + + public void setScriptName(String scriptName) { + this.scriptName = scriptName; + } + @Override public String toString() { return "ApiInfo{" + "id=" + id + ", apiGroupName='" + apiGroupName + '\'' + ", apiName='" + apiName + '\'' diff --git a/src/main/java/com/eactive/httpmockserver/script/Script.java b/src/main/java/com/eactive/httpmockserver/script/Script.java new file mode 100644 index 0000000..c4ce9ad --- /dev/null +++ b/src/main/java/com/eactive/httpmockserver/script/Script.java @@ -0,0 +1,6 @@ +package com.eactive.httpmockserver.script; + +public interface Script { + + public String postProcess(String requestMessage, String responseMessage) throws Exception; +} diff --git a/src/main/java/com/eactive/httpmockserver/script/ScriptController.java b/src/main/java/com/eactive/httpmockserver/script/ScriptController.java new file mode 100644 index 0000000..90aa60e --- /dev/null +++ b/src/main/java/com/eactive/httpmockserver/script/ScriptController.java @@ -0,0 +1,118 @@ +package com.eactive.httpmockserver.script; + +import com.eactive.httpmockserver.ApiManageRestController; +import com.eactive.httpmockserver.datatables.DataTablesRequest; +import com.eactive.httpmockserver.datatables.DataTablesResponse; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Example; +import org.springframework.data.domain.ExampleMatcher; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; + +import javax.tools.JavaCompiler; +import javax.tools.ToolProvider; +import javax.validation.Valid; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Optional; + +@Controller +public class ScriptController { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private ScriptInfoService scriptInfoService; + + @GetMapping("/manage/findAllScriptInfos") + public String getAllScriptInfoForDatatables(Pageable pageable, Model model) { + return "page/list-script-info"; + } + + @GetMapping(path = { "/manage/getScriptInfoForm", "/manage/getScriptInfoForm/{id}" }) + public String getScriptInfoForm(Model model, @PathVariable Optional id) throws IOException { + if (id.isPresent()) { + Optional optional = scriptInfoService.findById(id.get()); + if (optional.isPresent()) { + model.addAttribute("scriptInfo", optional.get()); + } else { + throw new IllegalArgumentException("No data, id: " + id.get()); + } + } else { + ScriptInfo spec = new ScriptInfo(); + InputStream is = getClass().getClassLoader().getResourceAsStream("basecodes/BaseScript.java.template"); + String baseCode = IOUtils.toString(is, "utf-8"); + spec.setScriptCode(baseCode); + model.addAttribute("scriptInfo", spec); + } + + return "page/add-edit-script-info"; + } + + @PostMapping("/manage/saveScriptInfo") + public String saveScriptInfo(@Valid ScriptInfo spec, BindingResult result, Model model) throws IOException, ClassNotFoundException { + if (result.hasErrors()) { + return "page/add-edit-script-info"; + } + ScriptLoader.getInstance().load(spec.getScriptName(), spec.getScriptCode()); + if (spec.getId() == null) { + scriptInfoService.save(spec); + } else { + scriptInfoService.update(spec); + } + + if (BooleanUtils.toBoolean(spec.getUseYn())) { + // 기존설정 useYn=N으로 수정 + scriptInfoService.setUnuseOthers(spec.getId()); + } + + return "redirect:/manage/findAllScriptInfos"; + } + @RequestMapping("/manage/deleteScriptInfo/{id}") + public String deleteScriptInfo(@PathVariable Long id) throws IOException, ClassNotFoundException { + if (id == null) { + throw new IllegalArgumentException("No data, id: " + id); + } + String scriptName = scriptInfoService.findById(id).get().getScriptName(); + ScriptLoader.getInstance().unLoad(scriptName); + scriptInfoService.delete(id); + + return "redirect:/manage/findAllScriptInfos"; + } + + @PostMapping("/manage/rest/scriptInfos") + @ResponseBody + public DataTablesResponse getAllScriptInfoForDatatables(@RequestBody DataTablesRequest req) { + Pageable pageable = ApiManageRestController.assignJpaPageable(req); + + // search option + Example example = null; + if (StringUtils.isNotBlank(req.getSearch().getValue())) { + ScriptInfo spec = new ScriptInfo(); + spec.setScriptName(req.getSearch().getValue()); + + ExampleMatcher matcher = ExampleMatcher.matchingAny().withMatcher("specName", + new ExampleMatcher.GenericPropertyMatcher().contains().ignoreCase()); + example = Example.of(spec, matcher); + } + + DataTablesResponse res = new DataTablesResponse( + scriptInfoService.findAllScriptInfos(example, pageable)); + res.setRecordsFiltered(scriptInfoService.getRecordsCount(example)); + res.setRecordsTotal(scriptInfoService.getRecordsCount(null)); + res.setDraw(req.getDraw()); + return res; + } +} diff --git a/src/main/java/com/eactive/httpmockserver/script/ScriptInfo.java b/src/main/java/com/eactive/httpmockserver/script/ScriptInfo.java new file mode 100644 index 0000000..c5c78c0 --- /dev/null +++ b/src/main/java/com/eactive/httpmockserver/script/ScriptInfo.java @@ -0,0 +1,67 @@ +package com.eactive.httpmockserver.script; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +@Entity +public class ScriptInfo implements Serializable { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotBlank + @Column(length = 500, nullable = false) + private String scriptName; + + @NotBlank + @Column(length = 4000, nullable = false) + private String scriptDesc; + + @Column + @Lob + private String scriptCode; + + @Column(length = 1) + private String useYn; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getScriptName() { + return scriptName; + } + + public void setScriptName(String scriptName) { + this.scriptName = scriptName; + } + + public String getScriptDesc() { + return scriptDesc; + } + + public void setScriptDesc(String scriptDesc) { + this.scriptDesc = scriptDesc; + } + + public String getScriptCode() { + return scriptCode; + } + + public void setScriptCode(String scriptCode) { + this.scriptCode = scriptCode; + } + + public String getUseYn() { + return useYn; + } + + public void setUseYn(String useYn) { + this.useYn = useYn; + } +} diff --git a/src/main/java/com/eactive/httpmockserver/script/ScriptInfoDao.java b/src/main/java/com/eactive/httpmockserver/script/ScriptInfoDao.java new file mode 100644 index 0000000..378f009 --- /dev/null +++ b/src/main/java/com/eactive/httpmockserver/script/ScriptInfoDao.java @@ -0,0 +1,16 @@ +package com.eactive.httpmockserver.script; + +import com.eactive.httpmockserver.socket.BytesMessageSpec; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +@Repository +public interface ScriptInfoDao extends JpaRepository { + ScriptInfo findFirstByUseYn(String useYn); + + @Modifying + @Query(value = "update ScriptInfo b set b.useYn='N' where b.id <> ?1") + void updateUnuseOthers(Long id); +} diff --git a/src/main/java/com/eactive/httpmockserver/script/ScriptInfoService.java b/src/main/java/com/eactive/httpmockserver/script/ScriptInfoService.java new file mode 100644 index 0000000..575c9e8 --- /dev/null +++ b/src/main/java/com/eactive/httpmockserver/script/ScriptInfoService.java @@ -0,0 +1,27 @@ +package com.eactive.httpmockserver.script; + +import org.springframework.data.domain.Example; +import org.springframework.data.domain.Pageable; + +import java.util.List; +import java.util.Optional; + +public interface ScriptInfoService { + public ScriptInfo findActiveScriptInfo(); + + public List findAllScriptInfos(Pageable pageable); + + public List findAllScriptInfos(Example example, Pageable pageable); + + public long getRecordsCount(Example example); + + public Optional findById(Long id); + + public ScriptInfo save(ScriptInfo spec); + + public ScriptInfo update(ScriptInfo spec); + + public void delete(Long id); + + public void setUnuseOthers(Long id); +} diff --git a/src/main/java/com/eactive/httpmockserver/script/ScriptInfoServiceImpl.java b/src/main/java/com/eactive/httpmockserver/script/ScriptInfoServiceImpl.java new file mode 100644 index 0000000..fbc9d62 --- /dev/null +++ b/src/main/java/com/eactive/httpmockserver/script/ScriptInfoServiceImpl.java @@ -0,0 +1,87 @@ +package com.eactive.httpmockserver.script; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Example; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +@Service +@Transactional(propagation = Propagation.SUPPORTS) +public class ScriptInfoServiceImpl implements ScriptInfoService { + @Autowired + private ScriptInfoDao dao; + + @Override + public ScriptInfo findActiveScriptInfo() { + return dao.findFirstByUseYn("Y"); + } + + @Override + public List findAllScriptInfos(Pageable pageable) { + Page pagedResult = dao.findAll(pageable); + if (pagedResult.hasContent()) { + return pagedResult.getContent(); + } else { + return new ArrayList(); + } + } + + @Override + public List findAllScriptInfos(Example example, Pageable pageable) { + if (example == null) { + return findAllScriptInfos(pageable); + } + + Page pagedResult = dao.findAll(example, pageable); + if (pagedResult.hasContent()) { + return pagedResult.getContent(); + } else { + return new ArrayList(); + } + } + + @Override + public Optional findById(Long id) { + return dao.findById(id); + } + + @Override + public long getRecordsCount(Example example) { + if (example == null) { + return dao.count(); + } else { + return dao.count(example); + } + } + + @Override + @Transactional(propagation = Propagation.REQUIRED, readOnly = false) + public ScriptInfo save(ScriptInfo spec) { + return dao.save(spec); + } + + @Override + @Transactional(propagation = Propagation.REQUIRED, readOnly = false) + public ScriptInfo update(ScriptInfo spec) { + return dao.save(spec); + } + + @Override + @Transactional(propagation = Propagation.REQUIRED, readOnly = false) + public void delete(Long id) { + dao.deleteById(id); + } + + @Override + @Transactional(propagation = Propagation.REQUIRED, readOnly = false) + public void setUnuseOthers(Long id) { + dao.updateUnuseOthers(id); + } +} diff --git a/src/main/java/com/eactive/httpmockserver/script/ScriptLoader.java b/src/main/java/com/eactive/httpmockserver/script/ScriptLoader.java new file mode 100644 index 0000000..776ce81 --- /dev/null +++ b/src/main/java/com/eactive/httpmockserver/script/ScriptLoader.java @@ -0,0 +1,82 @@ +package com.eactive.httpmockserver.script; + +import org.apache.commons.io.IOUtils; + +import javax.tools.JavaCompiler; +import javax.tools.ToolProvider; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.HashMap; +import java.util.Map; + +public class ScriptLoader{ + String path = ScriptLoader.class.getProtectionDomain().getCodeSource().getLocation().getPath(); + public static String DYNAMIC_BASE_PACKAGE = "com.eactive.httpmockserver.script.dynamic"; + public static String DYNAMIC_BASE_PATH = DYNAMIC_BASE_PACKAGE.replaceAll("[.]","/"); + + private static final ScriptLoader instance = new ScriptLoader(); + private Map> loadedClass; + + private ScriptLoader(){ + this.loadedClass = new HashMap<>(); + } + + public static ScriptLoader getInstance(){ + return instance; + } + + public Script newScript(String scriptName) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { + Class + + + + + + + diff --git a/src/main/resources/templates/page/list-script-info.html b/src/main/resources/templates/page/list-script-info.html new file mode 100644 index 0000000..60f15d8 --- /dev/null +++ b/src/main/resources/templates/page/list-script-info.html @@ -0,0 +1,155 @@ + + + + + + + + + +
+ +
+
+
+
+

스크립트 관리

+
+
+ +
+
+
+ +
+ + +
+
+
+
+
+
+

응답 송신 전 수행 할 스크립트, GUID 복제나 특정 예외전문등의 처리 수행 로직을 작성한다(java)

+
+
+ + + + + + + + + +
스크립트 명스크립트 설명수정삭제
+
+ +
+ +
+ +
+ +
+ +
+
+ + + + + + + + + + + + + + + + + +