Programming๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป/AxBoot

QueryDSL

Dodal 2021. 4. 19. 14:24

QueryDSL?

์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ๋กœ ๋ณต์žกํ•œ Creteria๋ฅผ ๋Œ€์ฒดํ•˜๋Š” JPQL๋นŒ๋”์ด๋‹ค.

๋ณต์žกํ•œ ์ฟผ๋ฆฌ์™€ ๋™์ ์ฟผ๋ฆฌ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ํ•ด๊ฒฐํ•ด์ฃผ๊ณ  ์ฟผ๋ฆฌ๋ฅผ ์ž๋ฐ” ์ฝ”๋“œ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ฌธ๋ฒ•์˜ค๋ฅ˜๋ฅผ ์ปดํŒŒ์ผ ๋‹จ๊ณ„์—์„œ ์žก์•„์ค„ ์ˆ˜ ์žˆ๋‹ค.


-Creteria๋Š” Java์ฝ”๋“œ๋ฅผ ์ด์šฉํ•ด JPQL์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ฃผ๋Š” ํƒ€์ž… ์„ธ์ดํ”„(Type-Safe: ํƒ€์ž…์— ์•ˆ์ •์  ์ฆ‰ ์–ด๋– ํ•œ ์˜คํผ๋ ˆ์ด์…˜(๋˜๋Š” ์—ฐ์‚ฐ)๋„ ์ •์˜๋˜์ง€ ์•Š์€ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด๋†“์ง€ ์•Š์€ ๊ฒƒ์ด๋‹ค. ์˜ˆ์ธก๋ถˆ๊ฐ€๋Šฅํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋‚ด์ง€ ์•Š๋Š” ๊ฒƒ์„ ๋œปํ•จ)๋ฅผ ์ œ๊ณตํ•˜๋Š” ์ฟผ๋ฆฌ์ด๋‹ค. SQL ์ฟผ๋ฆฌ๋ฅผ ๋Œ€์ฒดํ•ด HQL, JPQL์„ ์ž๋ฐ” ์ฝ”๋“œ๋กœ ์ด์šฉํ•ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด ์ค€๋‹ค.

 

-JPQL๋Š” JPA์˜ ์ผ๋ถ€๋กœ ์ •์˜๋œ ํ”Œ๋žซํผ ๋…๋ฆฝ์ ์ธ ๊ฐ์ฒด์ง€ํ–ฅ ์ฟผ๋ฆฌ์ด๋‹ค.

SQL์— ํฌ๊ฒŒ ์˜ํ–ฅ์„ ๋ฐ›์•„ SQL๋ฌธ๊ณผ ๋น„์Šทํ•˜์ง€๋งŒ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ํ…Œ์ด๋ธ”์— ์ง์ ‘ ์—ฐ๊ฒฐ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ

JPA ์—”ํ‹ฐํ‹ฐ์— ๋Œ€ํ•ด ๋™์ž‘ํ•œ๋‹ค. 


 

โ—DB 'Company'์— ๋Œ€ํ•œ ๊ฐœ์ฒด ๋“ฑ๋ก ๋ฐ ์‚ญ์ œ/์ˆ˜์ •/์กฐํšŒ ๊ธฐ๋Šฅ ๋งŒ๋“ค๊ธฐ

1. ์ง„ํ–‰ํ•˜๊ณ  ์žˆ๋Š” ํ”„๋กœ์ ํŠธ์—์„œ Companyservice๋‹จ์—์„œ ์ƒ์†๋œ

BaseService์— QueryDSL์˜ ๊ฐœ์ฒด๋ฅผ ๋“ฑ๋กํ•œ ํ›„,

import java.io.Serializable;
public class BaseService<T, ID extends Serializable> extends AXBootBaseService<T, ID> {
    protected QUserRole qUserRole = QUserRole.userRole;
    protected QAuthGroupMenu qAuthGroupMenu = QAuthGroupMenu.authGroupMenu;
    protected QCommonCode qCommonCode = QCommonCode.commonCode;
    protected QUser qUser = QUser.user;
    protected QProgram qProgram = QProgram.program;
    protected QUserAuth qUserAuth = QUserAuth.userAuth;
    protected QMenu qMenu = QMenu.menu;
    protected QCommonFile qCommonFile = QCommonFile.commonFile;
    protected QCompany qCompany = QCompany.company;
    protected AXBootJPAQueryDSLRepository<T, ID> repository;
    public BaseService() {
        super();
    }
    public BaseService(AXBootJPAQueryDSLRepository<T, ID> repository) {
        super(repository);
        this.repository = repository;
    }
}

 

 

2. CompanyService.java์— ์‚ฌ์šฉํ•  QueryDSL ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•จ.

   //QueryDSL
    public List<Company> getByQueryDsl(RequestParams<Company> requestParams) {
        String company = requestParams.getString("company", "");
        String ceo = requestParams.getString("ceo", "");
        String bizno = requestParams.getString("bizno", "");
        BooleanBuilder builder = new BooleanBuilder();
        if (isNotEmpty(company)) {
            builder.and(qCompany.companyNm.eq(company));
        }
        if (isNotEmpty(ceo)) {
            builder.and(qCompany.ceo.eq(ceo));
        }
        if (isNotEmpty(bizno)) {
            builder.and(qCompany.bizno.eq(bizno));
        }
        List<Company> companyList = select()
                .from(qCompany)
                .where(builder)
                .orderBy(qCompany.companyNm.asc())
                .fetch();
        return companyList;
    }

    @Transactional
    public void saveByQueryDsl(List<Company> request) {
        for (Company company: request) {
            if (company.isCreated()) {
                save(company);
            } else if (company.isModified()) {
                update(qCompany)
                        .set(qCompany.companyNm, company.getCompanyNm())
                        .set(qCompany.ceo, company.getCeo())
                        .where(qCompany.id.eq(company.getId()))
                        .execute();
            } else if (company.isDeleted()) {
                delete(qCompany)
                        .where(qCompany.id.eq(company.getId()))
                        .execute();
            }
        }
    }

3. CompanyController.java์— @ApiImplicitParams(์ €์žฅ๋œ ํ…Œ์ด๋ธ” ์ปฌ๋Ÿผ์— ๋ฐ์ดํ„ฐ ์กฐํšŒ๋กœ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ?)

@RequestMapping(value = "/QueryDsl", method = RequestMethod.GET, produces = APPLICATION_JSON)
@ApiImplicitParams({
        @ApiImplicitParam(name = "company", value = "ํšŒ์‚ฌ๋ช…", dataType = "String", paramType = "query"),
        @ApiImplicitParam(name = "ceo", value = "๋Œ€ํ‘œ์ž", dataType = "String", paramType = "query"),
        @ApiImplicitParam(name = "bizno", value = "์‚ฌ์—…์ž๋ฒˆํ˜ธ", dataType = "String", paramType = "query")
})
public Responses.ListResponse list2(RequestParams<Company> requestParams) {
    List<Company> list = companyService.getByQueryDsl(requestParams);
    return Responses.ListResponse.of(list);
}
@RequestMapping(value = "/QueryDsl", method = {RequestMethod.PUT}, produces = APPLICATION_JSON)
public ApiResponse save2(@RequestBody List<Company> request) {
    companyService.saveByQueryDsl(request);
    return ok();
}

 

4. company.jsp์—์„œ ํ™”๋ฉด๋‹จ์— ํ•ด๋‹นํ•˜๋Š” ๊ฐ’์„ ์ถ”์ถœํ•˜๊ธฐ ์œ„ํ•ด์„œ ๊ฐ inputํƒœ๊ทธ์— NAME๊ณผ ID๋ฅผ ๊ฐ™์€ ์ด๋ฆ„์œผ๋กœ

์š”์†Œ๋กœ ์ถ”๊ฐ€ํ•œ๋‹ค.

<div role="page-header">
    <ax:form name="searchView0">
        <ax:tbl clazz="ax-search-tbl" minWidth="500px">
            <ax:tr>
                <ax:td label='ํšŒ์‚ฌ๋ช…' width="300px">
                    <input type="text" name="company" id="company" class="form-control" />
                </ax:td>
                <ax:td label='๋Œ€ํ‘œ์ž' width="300px">
                    <input type="text" name="ceo" id="ceo" class="form-control" />
                </ax:td>
                <ax:td label='์‚ฌ์—…์ž๋ฒˆํ˜ธ' width="300px">
                    <input type="text" name="bizno" id="bizno" class="form-control" />
                </ax:td>
            </ax:tr>
        </ax:tbl>
    </ax:form>
    <div class="H10"></div>
</div>

 

5. company.js์—์„œ jsp์—์„œ ์ถ”๊ฐ€ํ–ˆ๋˜ name/id ์š”์†Œ๋กœ ๊ฐ’์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€.

fnObj.searchView = axboot.viewExtend(axboot.searchView, {
    initView: function () {
        this.target = $(document["searchView0"]);
        this.target.attr("onsubmit", "return ACTIONS.dispatch(ACTIONS.PAGE_SEARCH);");
        this.company = $("#company");
        this.ceo = $("#ceo");
        this.bizno = $("#bizno");
    },
    getData: function () {
        return {
            pageNumber: this.pageNumber,
            pageSize: this.pageSize,
            company: this.company.val(),
            ceo: this.ceo.val(),
            bizno: this.bizno.val()
        }
    }
});

 

โ—๋ฐ์ดํ„ฐ ์ˆ˜์ • ๊ธฐ๋Šฅ

 

1. company.js์—์„œ PAGE_SAVE์˜ type : put์˜์—ญ์— querydsl ๊ฒฝ๋กœ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ์ˆ˜์ •๊ธฐ๋Šฅ์„ ์™„์„ฑํ•œ๋‹ค.

   PAGE_SAVE: function (caller, act, data) {
        var saveList = [].concat(caller.gridView01.getData()); //modified์‚ญ์ œํ•จ
        saveList = saveList.concat(caller.gridView01.getData("deleted"));

        axboot.ajax({
            type: "PUT",
 //         url: "/api/v1/company",
            url: "/api/v1/company/QueryDsl",
            data: JSON.stringify(saveList),
            callback: function (res) {
                ACTIONS.dispatch(ACTIONS.PAGE_SEARCH);
                axToast.push("์ €์žฅ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค");
            }
        });
    },

 

โ—๋ฐ์ดํ„ฐ ์‚ญ์ œ๊ธฐ๋Šฅ

getData: function (_type) {
        var list = [];
        var _list = this.target.getList(_type);

        if (_type == "modified" || _type == "deleted") {
            list = ax5.util.filter(_list, function () {
               // delete this.deleted;
              //  return this.key;
              return this.id; // ๊ฐ์ฒด์•ˆ์—๋Š” key๊ฐ’์ด ์—†์œผ๋ฏ€๋กœ id๊ฐ’์„ ๋ฐ›์•„์˜จ๋‹ค.
            });
        } else {
            list = _list;
        }
        return list;
    },

์ธํ…”๋ฆฌ์ œ์ด ์ปค๋ฎค๋‹ˆํ‹ฐ ๋ฒ„์ „์œผ๋กœ ํ™”๋ฉด๋‹จ์„ ์‹ค์‹œ๊ฐ„ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๋Š” dependency

<dependency>
    <groupId>org.assertj</groupId>
    <artifactId>assertj-core</artifactId>
    <version>3.12.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
</dependency>
๋ฐ˜์‘ํ˜•