{"id":1536,"date":"2020-12-27T22:47:08","date_gmt":"2020-12-27T13:47:08","guid":{"rendered":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=1536"},"modified":"2021-01-24T20:12:47","modified_gmt":"2021-01-24T11:12:47","slug":"generic-type-%ec%9d%84-%ec%9d%b4%ec%9a%a9%ed%95%9c-restcontroller-%ec%bd%94%eb%93%9c-%ec%a4%91%eb%b3%b5%ec%a0%9c%ea%b1%b0","status":"publish","type":"post","link":"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=1536","title":{"rendered":"Generic type \uc744 \uc774\uc6a9\ud55c RestController \ucf54\ub4dc \uc911\ubcf5\uc81c\uac70"},"content":{"rendered":"<h1>Generic type \uc744 \uc774\uc6a9\ud55c RestController \ucf54\ub4dc \uc911\ubcf5\uc81c\uac70<\/h1>\n<p><code>RestController<\/code> \ub97c \uc791\uc131\ud558\ub2e4 \ubcf4\uba74 95% \uc758 \ucf54\ub4dc\uac00 \ubc18\ubcf5\ub418\ub294 \uac83\uc744 \ub290\ub07c\uac8c \ub41c\ub2e4.<\/p>\n<p><code>Generic type<\/code> \uc744 \uc774\uc6a9\ud574 \ucf54\ub4dc\uc911\ubcf5\uc744 \uc81c\uac70\ud574 \ubcf4\uc790.<\/p>\n<h2>CustomGenericService<\/h2>\n<pre><code class=\"language-java\">\/**\n *\n * CustomGenericService - \uc11c\ube44\uc2a4\uc758 \uacf5\ud1b5 \uae30\ub2a5 \ucd94\uc0c1\ud654(CRUD)\n * \uc7ac\uc815\uc758\uac00 \ud544\uc694\ud55c \uae30\ub2a5\uc740 @Override\ud574\uc11c \uc0ac\uc6a9\ud560\uac83\n *\n * @author skyer9@gmail.com\n *\n * @param &lt;D&gt; DTO Type\n * @param &lt;E&gt; Entity Type\n * @param &lt;KD&gt; Key DTO Type\n * @param &lt;KE&gt; Key Entity key type\n *\/\n\npublic abstract class CustomGenericService&lt;D, E, KD, KE&gt; {\n\n    protected JpaRepository&lt;E, KE&gt; repository;\n    protected final String title;\n\n    public CustomGenericService(JpaRepository&lt;E, KE&gt; repository, String title) {\n\n        this.repository = repository;\n        this.title = title;\n    }\n\n    \/\/ \uc0dd\uc131\n    @Transactional\n    public D create(D d) {\n\n        E e = newEntity();\n        updateFromDto(d, e);\n\n        return toDto(repository.save(e));\n    }\n\n    \/\/ \uccb4\ud06c \ubc0f \uc0dd\uc131\n    @Transactional\n    public D create(KD id, D d) throws DataExistsException {\n\n        KE ke = toKeyEntity(id);\n\n        if (get(ke, false) != null) {\n            throw new DataExistsException(title + &quot;\uc774(\uac00) \uc774\ubbf8 \uc874\uc7ac\ud569\ub2c8\ub2e4.&quot;);\n        }\n\n        E e = newEntity(ke);\n        updateFromDto(d, e);\n\n        return toDto(repository.save(e));\n    }\n\n    \/\/ \uc218\uc815\n    @Transactional\n    public void update(KD id, D d) {\n\n        E e = get(toKeyEntity(id), true);\n        updateFromDto(d, e);\n        repository.save(e);\n    }\n\n    \/\/ DTO \uc870\ud68c\n    @Transactional(readOnly = true)\n    public D select(KD id) {\n\n        return toDto(get(toKeyEntity(id), true));\n    }\n\n    \/\/ Entity \ubc18\ud658\n    @Transactional\n    public E get(KE id, boolean throwExceptionIfNotExists) {\n\n        E e = repository.findById(id).orElse(null);\n\n        if (throwExceptionIfNotExists &amp;&amp; (e == null)) {\n            throw new DataNotFoundException(title + &quot;\uc774(\uac00) \uc874\uc7ac\ud558\uc9c0 \uc54a\uc2b5\ub2c8\ub2e4.&quot;);\n        } else {\n            return e;\n        }\n    }\n\n    @Transactional\n    public E get(KE id) {\n        Optional&lt;E&gt; o = repository.findById(id);\n        return o.orElseGet(() -&gt; newEntity(id));\n    }\n\n    public abstract SearchResponseDto search(Map&lt;String, String&gt; params);\n\n    protected List&lt;D&gt; toDto(List&lt;E&gt; lst) {\n\n        return lst.stream().map(this::toDto).collect(Collectors.toList());\n    }\n\n    protected abstract D toDto(E e);\n    protected abstract E toEntity(D e);\n    \/\/ protected abstract KD toKeyDto(KE e);\n    protected abstract KE toKeyEntity(KD e);\n    protected abstract void updateFromDto(D d, E e);\n    protected abstract E newEntity();\n    protected abstract E newEntity(KE e);\n}<\/code><\/pre>\n<h2>BaseRestController<\/h2>\n<pre><code class=\"language-java\">\/**\n *\n * CustomGenericService - \uc11c\ube44\uc2a4\uc758 \uacf5\ud1b5 \uae30\ub2a5 \ucd94\uc0c1\ud654(CRUD)\n * \uc7ac\uc815\uc758\uac00 \ud544\uc694\ud55c \uae30\ub2a5\uc740 @Override\ud574\uc11c \uc0ac\uc6a9\ud560\uac83\n *\n * @author skyer9@gmail.com\n *\n * @param &lt;D&gt; DTO Type\n * @param &lt;E&gt; Entity Type\n * @param &lt;KD&gt; Key DTO Type\n * @param &lt;KE&gt; Key Entity key type\n *\/\n\npublic class BaseRestController&lt;D, E, KD, KE&gt; {\n\n    protected final CustomGenericService&lt;D, E, KD, KE&gt; service;\n\n    public BaseRestController(CustomGenericService&lt;D, E, KD, KE&gt; service) {\n        this.service = service;\n    }\n\n    \/\/ PK \uc790\ub3d9\uc0dd\uc131\n    public ResponseEntity&lt;?&gt; create(D dto) {\n\n        D created = service.create(dto);\n\n        return ResponseEntity.ok(new ApiResponseWithData(ResponseCode.OK, created));\n    }\n\n    \/\/ PK \uc218\ub3d9\ubd80\uc5ec(PK \uccb4\ud06c)\n    public ResponseEntity&lt;?&gt; create(KD kd, D dto) {\n\n        D created = service.create(kd, dto);\n\n        return ResponseEntity.ok(new ApiResponseWithData(ResponseCode.OK, created));\n    }\n\n    public ResponseEntity&lt;?&gt; update(KD keyDto, D dto) {\n\n        service.update(keyDto, dto);\n        return ResponseEntity.ok(new ApiResponseMessage(ResponseCode.OK));\n    }\n\n    public ResponseEntity&lt;?&gt; select(KD keyDto) {\n\n        D dto = service.select(keyDto);\n\n        return ResponseEntity.ok(new ApiResponseWithData(ResponseCode.OK, dto));\n    }\n\n    public ResponseEntity&lt;?&gt; search(Map&lt;String, String&gt; params) {\n\n        SearchResponseDto searchResponseDto = service.search(params);\n\n        return ResponseEntity.ok(\n                new ApiResponseWithPaging(ResponseCode.OK,\n                        searchResponseDto.getResults(),\n                        searchResponseDto.getPageable(),\n                        searchResponseDto.getTotalCount()\n                )\n        );\n    }\n}<\/code><\/pre>\n<h2>BrandsService<\/h2>\n<pre><code class=\"language-java\">@Service\npublic class BrandsService extends CustomGenericService&lt;BrandsDto, Brands, String, String&gt; {\n\n    private final BrandsMapper mapper = Mappers.getMapper(BrandsMapper.class);\n\n    @PersistenceContext\n    private final EntityManager entityManager;\n\n    public BrandsService(JpaRepository&lt;Brands, String&gt; repository, EntityManager entityManager) {\n        super(repository, &quot;\ube0c\ub79c\ub4dc&quot;);\n        this.entityManager = entityManager;\n    }\n\n    @Override\n    @Transactional(readOnly = true)\n    public SearchResponseDto search(Map&lt;String, String&gt; params) {\n\n        BrandSearchDto dto = new BrandSearchDto(params);\n        Pageable pageable = PageRequest.of(dto.getPageNo(), dto.getPageSize());\n\n        StoredProcedureQuery sp =\n                entityManager.createNamedStoredProcedureQuery(Brands.NamedQuery_GetBrandList);\n        sp.setParameter(&quot;_pageNo&quot;, pageable.getPageNumber());\n        sp.setParameter(&quot;_pageSize&quot;, pageable.getPageSize());\n        sp.setParameter(&quot;_partnerId&quot;, dto.getPartnerId());\n        sp.setParameter(&quot;_brandId&quot;, dto.getBrandId());\n        sp.setParameter(&quot;_useyn&quot;, dto.getUseyn());\n        sp.execute();\n\n        @SuppressWarnings(&quot;unchecked&quot;)\n        List&lt;Object&gt; results = toDto(sp.getResultList());\n        int totalCount = (int) sp.getOutputParameterValue(&quot;RESULT&quot;);\n\n        return new SearchResponseDto(results, pageable, totalCount);\n    }\n\n    @Override\n    protected BrandsDto toDto(Brands brands) {\n        return mapper.to(brands);\n    }\n\n    @Override\n    protected Brands toEntity(BrandsDto e) {\n        return mapper.to(e);\n    }\n\n    @Override\n    protected String toKeyEntity(String e) {\n        return e;\n    }\n\n    @Override\n    protected void updateFromDto(BrandsDto dto, Brands brands) {\n        mapper.updateFromDto(dto, brands);\n    }\n\n    @Override\n    protected Brands newEntity() {\n        return new Brands();\n    }\n\n    @Override\n    protected Brands newEntity(String e) {\n        return new Brands(e);\n    }\n}<\/code><\/pre>\n<h2>BrandsApiController<\/h2>\n<pre><code class=\"language-java\">@Api(tags = { &quot;12. \ube0c\ub79c\ub4dc \ub9ac\uc2a4\ud2b8&quot; })\n@RestController\n@RequestMapping(&quot;\/v1\/brands&quot;)\npublic class BrandsApiController extends BaseRestController&lt;BrandsDto, Brands, String, String&gt; {\n\n    public BrandsApiController(BrandsService service) {\n        super(service);\n    }\n\n    @Override\n    @ApiOperation(value = &quot;\ube0c\ub79c\ub4dc \ub4f1\ub85d&quot;, notes = &quot;\uc2e0\uaddc \ube0c\ub79c\ub4dc\ub97c \ub4f1\ub85d\ub4f1\ub85d\ud569\ub2c8\ub2e4.&quot;)\n    @PostMapping(&quot;\/&quot;)\n    public ResponseEntity&lt;?&gt; create(@RequestBody BrandsDto dto) {\n        return super.create(dto.getBrandId(), dto);\n    }\n\n    @Override\n    @ApiOperation(value = &quot;\ube0c\ub79c\ub4dc \uc218\uc815&quot;, notes = &quot;\ube0c\ub79c\ub4dc\ub97c \uc218\uc815\ud569\ub2c8\ub2e4.&quot;)\n    @ApiImplicitParams({\n            @ApiImplicitParam(name = &quot;id&quot;, value = &quot;\ube0c\ub79c\ub4dc ID&quot;, required = true, dataType = &quot;string&quot;, paramType = &quot;path&quot;, defaultValue = &quot;&quot;),\n    })\n    @PutMapping(&quot;\/{id}&quot;)\n    public ResponseEntity&lt;?&gt; update(@PathVariable String id, @RequestBody BrandsDto dto) {\n        return super.update(id, dto);\n    }\n\n    @Override\n    @ApiOperation(value = &quot;\ube0c\ub79c\ub4dc \uc870\ud68c&quot;, notes = &quot;\ube0c\ub79c\ub4dc\uc744 \uc870\ud68c\ud569\ub2c8\ub2e4.&quot;)\n    @ApiImplicitParams({\n            @ApiImplicitParam(name = &quot;id&quot;, value = &quot;\ube0c\ub79c\ub4dc ID&quot;, required = true, dataType = &quot;string&quot;, paramType = &quot;path&quot;, defaultValue = &quot;&quot;),\n    })\n    @GetMapping(&quot;\/{id}&quot;)\n    public ResponseEntity&lt;?&gt; select(@PathVariable String id) {\n        return super.select(id);\n    }\n\n    @Override\n    @ApiOperation(value = &quot;\ube0c\ub79c\ub4dc \uac80\uc0c9&quot;, notes = &quot;\ube0c\ub79c\ub4dc\ub97c \uac80\uc0c9\ud569\ub2c8\ub2e4.&quot;)\n    @GetMapping(&quot;\/&quot;)\n    public ResponseEntity&lt;?&gt; search(@RequestParam Map&lt;String, String&gt; params) {\n        return super.search(params);\n    }\n}<\/code><\/pre>\n<p>\uc911\ubcf5\ub41c \ucf54\ub4dc\uac00 \uc0c1\ub2f9\ub7c9 \uc81c\uac70\ub41c\ub2e4.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Generic type \uc744 \uc774\uc6a9\ud55c RestController \ucf54\ub4dc \uc911\ubcf5\uc81c\uac70 RestController \ub97c \uc791\uc131\ud558\ub2e4 \ubcf4\uba74 95% \uc758 \ucf54\ub4dc\uac00 \ubc18\ubcf5\ub418\ub294 \uac83\uc744 \ub290\ub07c\uac8c \ub41c\ub2e4. Generic type \uc744 \uc774\uc6a9\ud574 \ucf54\ub4dc\uc911\ubcf5\uc744 \uc81c\uac70\ud574 \ubcf4\uc790. CustomGenericService \/** * * CustomGenericService &#8211; \uc11c\ube44\uc2a4\uc758 \uacf5\ud1b5 \uae30\ub2a5 \ucd94\uc0c1\ud654(CRUD) * \uc7ac\uc815\uc758\uac00 \ud544\uc694\ud55c \uae30\ub2a5\uc740 @Override\ud574\uc11c \uc0ac\uc6a9\ud560\uac83 * * @author skyer9@gmail.com * * @param &lt;D&gt; DTO Type * @param &lt;E&gt; Entity\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.skyer9.pe.kr\/wordpress\/?p=1536\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-1536","post","type-post","status-publish","format-standard","hentry","category-spring-boot-2-1"],"_links":{"self":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1536","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1536"}],"version-history":[{"count":3,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1536\/revisions"}],"predecessor-version":[{"id":1582,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/1536\/revisions\/1582"}],"wp:attachment":[{"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1536"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1536"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.skyer9.pe.kr\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1536"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}