diff --git a/src/main/java/com/xit/biz/ctgy/auth/service/IAuthMinService.java b/src/main/java/com/xit/biz/ctgy/auth/service/IAuthMinService.java index c0a06f1..060a9f0 100644 --- a/src/main/java/com/xit/biz/ctgy/auth/service/IAuthMinService.java +++ b/src/main/java/com/xit/biz/ctgy/auth/service/IAuthMinService.java @@ -2,7 +2,6 @@ package com.xit.biz.ctgy.auth.service; import com.xit.biz.cmm.entity.CmmUser; import com.xit.biz.ctgy.dto.LoginMinRequestDto; -import com.xit.core.oauth2.api.dto.LoginRequestDto; import com.xit.core.oauth2.api.dto.TokenDto; import com.xit.core.oauth2.api.dto.TokenRequestDto; diff --git a/src/main/java/com/xit/biz/ctgy/controller/BoardController.java b/src/main/java/com/xit/biz/ctgy/controller/BoardController.java index 372f1b6..cc43fb8 100644 --- a/src/main/java/com/xit/biz/ctgy/controller/BoardController.java +++ b/src/main/java/com/xit/biz/ctgy/controller/BoardController.java @@ -1,7 +1,6 @@ package com.xit.biz.ctgy.controller; -import com.xit.biz.ctgy.dto.MinCivBoard680Dto; -import com.xit.biz.ctgy.dto.struct.MinCivBoard680Mapstruct; +import com.xit.biz.ctgy.dto.BoardDto; import com.xit.biz.ctgy.service.IBoardService; import com.xit.core.api.IRestResponse; import com.xit.core.api.RestResponse; @@ -11,14 +10,12 @@ import io.swagger.v3.oas.annotations.Parameters; import io.swagger.v3.oas.annotations.enums.ParameterIn; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.mapstruct.factory.Mappers; import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; @Tag(name = "BoardController", description = "게시글 관리") @RestController @@ -29,7 +26,6 @@ public class BoardController { private final IBoardService service; - private final MinCivBoard680Mapstruct mapstruct = Mappers.getMapper(MinCivBoard680Mapstruct.class); // TODO :: 파라메터 정의 필요 @Operation(summary = "게시글 목록 조회" , description = "게시글 목록 조회") @@ -42,10 +38,25 @@ public class BoardController { @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity findMinCivBoard680s( @Parameter(hidden = true) - final MinCivBoard680Dto dto, + final BoardDto dto, @Parameter(hidden = true) final Pageable pageable) { - return RestResponse.of(service.findAll(mapstruct.toEntity(dto), pageable)); + return RestResponse.of(service.findAll(dto, pageable)); } + @Operation(summary = "게시글 조회수 증가" , description = "게시글 조회수 증가") + @Parameters({ + @Parameter(in = ParameterIn.PATH, name = "ciCode", description = "게시글번호", required = true, example = "18"), + }) + @PutMapping(value = "/hit/{ciCode}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity modifyByCiCode(@PathVariable final Long ciCode) { + return RestResponse.of(service.modifyByCiCode(ciCode)); + } + + @Operation(summary = "게시글 등록" , description = "게시글 등록") + @PostMapping(produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity saveBoard(BoardDto dto) { + service.saveBoard(dto); + return RestResponse.of(HttpStatus.OK); + } } diff --git a/src/main/java/com/xit/biz/ctgy/dto/MinCivBoard680Dto.java b/src/main/java/com/xit/biz/ctgy/dto/BoardDto.java similarity index 87% rename from src/main/java/com/xit/biz/ctgy/dto/MinCivBoard680Dto.java rename to src/main/java/com/xit/biz/ctgy/dto/BoardDto.java index 7670b4c..8cc25e3 100644 --- a/src/main/java/com/xit/biz/ctgy/dto/MinCivBoard680Dto.java +++ b/src/main/java/com/xit/biz/ctgy/dto/BoardDto.java @@ -3,19 +3,14 @@ package com.xit.biz.ctgy.dto; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; import java.io.Serializable; -@Schema(name = "MinCivBoard680Dto", description = "게시판") +@Schema(name = "BoardDto", description = "게시판") @Getter @Setter @AllArgsConstructor @NoArgsConstructor -public class MinCivBoard680Dto implements Serializable { - private static final long SerialVersionUID = 1L; +public class BoardDto { @Schema(title = "게시판코드", example = " ", description = "Input Description...") private Long ciCode; @@ -61,4 +56,7 @@ public class MinCivBoard680Dto implements Serializable { @Schema(required = false, title = "내용", example = " ", description = "Input Description...") private String ciContents; + + @Schema(required = false, title = "IP", example = " ", description = "") + private String ciIp; } diff --git a/src/main/java/com/xit/biz/ctgy/dto/struct/MinCivBoard680Mapstruct.java b/src/main/java/com/xit/biz/ctgy/dto/struct/MinCivBoard680Mapstruct.java index cc65816..47ad23b 100644 --- a/src/main/java/com/xit/biz/ctgy/dto/struct/MinCivBoard680Mapstruct.java +++ b/src/main/java/com/xit/biz/ctgy/dto/struct/MinCivBoard680Mapstruct.java @@ -1,12 +1,12 @@ package com.xit.biz.ctgy.dto.struct; -import com.xit.biz.ctgy.dto.MinCivBoard680Dto; +import com.xit.biz.ctgy.dto.BoardDto; import com.xit.biz.ctgy.entity.MinCivBoard680; import com.xit.core.support.jpa.mapstruct.IMapstruct; import com.xit.core.support.jpa.mapstruct.MapStructMapperConfig; import org.mapstruct.Mapper; @Mapper(config = MapStructMapperConfig.class) -public interface MinCivBoard680Mapstruct extends IMapstruct { +public interface MinCivBoard680Mapstruct extends IMapstruct { } diff --git a/src/main/java/com/xit/biz/ctgy/entity/MinCivBoard680.java b/src/main/java/com/xit/biz/ctgy/entity/MinCivBoard680.java index a1b14ac..3d1a4b5 100644 --- a/src/main/java/com/xit/biz/ctgy/entity/MinCivBoard680.java +++ b/src/main/java/com/xit/biz/ctgy/entity/MinCivBoard680.java @@ -1,5 +1,7 @@ package com.xit.biz.ctgy.entity; +import com.xit.biz.ctgy.CtgyConstants; +import com.xit.core.oauth2.utils.HeaderUtil; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; import org.hibernate.annotations.DynamicInsert; @@ -8,6 +10,8 @@ import org.springframework.data.domain.Persistable; import javax.persistence.*; import java.io.Serializable; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; @Schema(name = "MinCivBoard680", description = "게시판") @Table(name = "min_civ_board680", schema = "", catalog = "") @@ -31,6 +35,7 @@ public class MinCivBoard680 implements Persistable { @Schema(required = false, title = "제목", example = " ", description = "Input Description...") @Column(name = "ci_title", nullable = true) + @Setter private String ciTitle; @Schema(required = false, title = "사용자아이디", example = " ", description = "Input Description...") @@ -79,12 +84,33 @@ public class MinCivBoard680 implements Persistable { @Schema(required = false, title = "내용", example = " ", description = "Input Description...") @Column(name = "ci_contents", nullable = true) + @Setter private String ciContents; @Schema(required = false, title = "IP", example = " ", description = "Input Description...") @Column(name = "ci_ip", nullable = true) private String ciIp; + @PrePersist + public void onPrePersist(){ + LocalDateTime localDateTime = LocalDateTime.now(); + this.ciNalja = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + this.ciTime = localDateTime.format(DateTimeFormatter.ofPattern("HH:mm")); + this.ciId = HeaderUtil.getUserId(); + this.ciPwd = this.ciId; + this.ciName = HeaderUtil.getUserName(); + this.ciHit = 0L; + } + + @PreUpdate + public void onPreUpdate(){ +// LocalDateTime localDateTime = LocalDateTime.now(); +// this.inNalja = localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); +// this.inTime = localDateTime.format(DateTimeFormatter.ofPattern("HH:mm")); +// this.inName = HeaderUtil.getUserName(); +// this.inHit = this.inHit + 1; + } + @Override public Long getId() { return this.ciCode; diff --git a/src/main/java/com/xit/biz/ctgy/repository/IBoardRepository.java b/src/main/java/com/xit/biz/ctgy/repository/IBoardRepository.java index 12d7df2..1aa63b9 100644 --- a/src/main/java/com/xit/biz/ctgy/repository/IBoardRepository.java +++ b/src/main/java/com/xit/biz/ctgy/repository/IBoardRepository.java @@ -6,6 +6,14 @@ import org.springframework.data.domain.Example; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; public interface IBoardRepository extends JpaRepository, IBoardRepositoryCustom { + + @Query(value = "SELECT max(e.ci_code) + 1 FROM min_civ_board680 e", nativeQuery = true) + Long getCiCode(); + @Modifying(clearAutomatically = true) + @Query("UPDATE MinCivBoard680 m SET m.ciHit = m.ciHit + 1 WHERE m.ciCode = :ciCode") + int updateInHitForMinCivBoard680(Long ciCode); } diff --git a/src/main/java/com/xit/biz/ctgy/repository/IBoardRepositoryCustom.java b/src/main/java/com/xit/biz/ctgy/repository/IBoardRepositoryCustom.java index ef0a966..463930a 100644 --- a/src/main/java/com/xit/biz/ctgy/repository/IBoardRepositoryCustom.java +++ b/src/main/java/com/xit/biz/ctgy/repository/IBoardRepositoryCustom.java @@ -1,10 +1,10 @@ package com.xit.biz.ctgy.repository; -import com.xit.biz.ctgy.entity.MinCivBoard680; +import com.xit.biz.ctgy.dto.BoardDto; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; public interface IBoardRepositoryCustom { - Page findAll2(final MinCivBoard680 entity, Pageable pageable); + Page findAll(final BoardDto dto, Pageable pageable); } diff --git a/src/main/java/com/xit/biz/ctgy/repository/IBoardRepositoryImpl.java b/src/main/java/com/xit/biz/ctgy/repository/IBoardRepositoryImpl.java index e05e3d4..e7c5878 100644 --- a/src/main/java/com/xit/biz/ctgy/repository/IBoardRepositoryImpl.java +++ b/src/main/java/com/xit/biz/ctgy/repository/IBoardRepositoryImpl.java @@ -1,35 +1,78 @@ package com.xit.biz.ctgy.repository; +import com.querydsl.core.QueryResults; +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; -import com.xit.biz.ctgy.entity.MinCivBoard680; +import com.xit.biz.ctgy.dto.BoardDto; +import com.xit.core.util.Checks; import lombok.AllArgsConstructor; import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; +import java.util.ArrayList; +import java.util.List; + +import static com.xit.biz.ctgy.entity.QMinCivBoard680.minCivBoard680; +import static com.xit.biz.ctgy.entity.QMinUserinfo.minUserinfo; + @AllArgsConstructor public class IBoardRepositoryImpl implements IBoardRepositoryCustom{ private final JPAQueryFactory queryFactory; @Override - public Page findAll2(final MinCivBoard680 entity, Pageable pageable){ - /* - SELECT Ci_code, - Ci_name, - ci_contentNo, - Ci_title, - Ci_nalja, - Ci_step, - Ci_revel, - Ci_ref, - ci_hit -FROM MIN_CIV_BOARD680 -WHERE Ci_code IN (SELECT Ci_code - FROM (SELECT Ci_code, rownum RCNT - FROM MIN_CIV_BOARD680 "& strSearchSQL1 &" - ORDER BY Ci_ref DESC, ci_step ASC, Ci_code DESC)) - */ - - return null; + public Page findAll(final BoardDto dto, Pageable pageable){ + + // 커버링 인덱스로 대상 조회 + QueryResults ciCodes = queryFactory + .select(minCivBoard680.ciCode) + .from(minCivBoard680) + .where(ciTitleLike(dto.getCiTitle()), ciNameLike(dto.getCiName())) + .orderBy(minCivBoard680.ciRef.desc(), minCivBoard680.ciStep.asc(), minCivBoard680.ciCode.desc()) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetchResults(); + + if (Checks.isEmpty(ciCodes)) { + new PageImpl<>(new ArrayList<>(), pageable, 0); + } + + List rslt = queryFactory + .select(Projections.fields( + BoardDto.class, + minCivBoard680.ciCode, + minUserinfo.name.as("ciName"), + minCivBoard680.ciContentno, + minCivBoard680.ciTitle, + minCivBoard680.ciContents, + minCivBoard680.ciNalja, + minCivBoard680.ciStep, + minCivBoard680.ciRevel, + minCivBoard680.ciRef, + minCivBoard680.ciHit, + minCivBoard680.ciPass, + minCivBoard680.ciId + )) + .from(minCivBoard680) + .leftJoin(minUserinfo) + .on(minCivBoard680.ciId.eq(minUserinfo.userid)) + .where(minCivBoard680.ciCode.in(ciCodes.getResults())) + .orderBy(minCivBoard680.ciRef.desc(), minCivBoard680.ciStep.asc(), minCivBoard680.ciCode.desc()) + .fetch(); + + return new PageImpl<>(rslt, pageable, ciCodes.getTotal()); } + + private BooleanExpression ciTitleLike(String ciTitle){ + if(Checks.isEmpty(ciTitle)) return null; + return minCivBoard680.ciTitle.contains(ciTitle); + } + + private BooleanExpression ciNameLike(String ciName){ + if(Checks.isEmpty(ciName)) return null; + return minCivBoard680.ciName.contains(ciName); + } + } diff --git a/src/main/java/com/xit/biz/ctgy/repository/IResidentAndDisabledRepositoryImpl.java b/src/main/java/com/xit/biz/ctgy/repository/IResidentAndDisabledRepositoryImpl.java index 327e6d5..3f04de6 100644 --- a/src/main/java/com/xit/biz/ctgy/repository/IResidentAndDisabledRepositoryImpl.java +++ b/src/main/java/com/xit/biz/ctgy/repository/IResidentAndDisabledRepositoryImpl.java @@ -42,7 +42,7 @@ public class IResidentAndDisabledRepositoryImpl implements IResidentAndDisabledR public Page findJudgeDatas(@NotNull final String scDatagb, Pageable pageable) { // 커버링 인덱스로 대상 조회 - QueryResults scCodeList = queryFactory + QueryResults scCodes = queryFactory .select(gnRecallSc.scCode) .from(gnRecallSc) .where(gnRecallSc.scDatagb.eq(scDatagb)) @@ -52,7 +52,7 @@ public class IResidentAndDisabledRepositoryImpl implements IResidentAndDisabledR .fetchResults(); // 대상이 없을 경우 추가 쿼리 수행 할 필요 없이 바로 반환 - if (Checks.isEmpty(scCodeList)) { + if (Checks.isEmpty(scCodes)) { new PageImpl<>(new ArrayList<>(), pageable, 0); } @@ -92,11 +92,11 @@ public class IResidentAndDisabledRepositoryImpl implements IResidentAndDisabledR "scStateNm") )) .from(gnRecallSc) - .where(gnRecallSc.scCode.in(scCodeList.getResults())) + .where(gnRecallSc.scCode.in(scCodes.getResults())) .orderBy(gnRecallSc.scCode.desc()) .fetch(); - return new PageImpl<>(rslt, pageable, scCodeList.getTotal()); + return new PageImpl<>(rslt, pageable, scCodes.getTotal()); } @Override diff --git a/src/main/java/com/xit/biz/ctgy/service/IBoardService.java b/src/main/java/com/xit/biz/ctgy/service/IBoardService.java index 7e45208..5b3c25e 100644 --- a/src/main/java/com/xit/biz/ctgy/service/IBoardService.java +++ b/src/main/java/com/xit/biz/ctgy/service/IBoardService.java @@ -1,11 +1,16 @@ package com.xit.biz.ctgy.service; +import com.xit.biz.ctgy.dto.BoardDto; import com.xit.biz.ctgy.entity.MinCivBoard680; -import com.xit.core.support.jpa.IJpaOperation; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; public interface IBoardService { - Page findAll(final MinCivBoard680 minCivBoard680, Pageable pageable); + Page findAll(final BoardDto dto, Pageable pageable); + Page findAll2(final MinCivBoard680 entity, Pageable pageable); + + int modifyByCiCode(Long ciCode); + + void saveBoard(BoardDto dto); } diff --git a/src/main/java/com/xit/biz/ctgy/service/impl/BoardService.java b/src/main/java/com/xit/biz/ctgy/service/impl/BoardService.java index c9c51a5..86c8aa4 100644 --- a/src/main/java/com/xit/biz/ctgy/service/impl/BoardService.java +++ b/src/main/java/com/xit/biz/ctgy/service/impl/BoardService.java @@ -1,14 +1,22 @@ package com.xit.biz.ctgy.service.impl; +import com.xit.biz.ctgy.dto.BoardDto; +import com.xit.biz.ctgy.dto.struct.MinCivBoard680Mapstruct; import com.xit.biz.ctgy.entity.MinCivBoard680; import com.xit.biz.ctgy.repository.IBoardRepository; import com.xit.biz.ctgy.service.IBoardService; +import com.xit.core.constant.ErrorCode; +import com.xit.core.exception.CustomBaseException; import com.xit.core.support.jpa.JpaUtil; +import com.xit.core.util.Checks; +import com.xit.core.util.CommUtil; import lombok.AllArgsConstructor; +import org.mapstruct.factory.Mappers; import org.springframework.data.domain.Example; import org.springframework.data.domain.ExampleMatcher; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -19,17 +27,56 @@ import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatc public class BoardService implements IBoardService { private final IBoardRepository repository; + private final PasswordEncoder passwordEncoder; + private final MinCivBoard680Mapstruct mapstruct = Mappers.getMapper(MinCivBoard680Mapstruct.class); @Transactional(readOnly = true) - public Page findAll(final MinCivBoard680 entity, Pageable pageable) { - //Sort sort = Sort.by(Sort.Direction.ASC, "codeOrdr"); + public Page findAll(final BoardDto dto, Pageable pageable) { + pageable = JpaUtil.getPagingInfo(pageable); + return repository.findAll(dto, pageable); + } + + @Transactional(readOnly = true) + public Page findAll2(final MinCivBoard680 entity, Pageable pageable) { pageable = JpaUtil.getPagingInfo(pageable); ExampleMatcher exampleMatcher = ExampleMatcher.matchingAll() .withMatcher("ciTitle", contains()) .withMatcher("ciName", contains()); Example example = Example.of(entity, exampleMatcher); - Page page = repository.findAll(example, pageable); - // List userList = page.getContent(); - return page; + return repository.findAll(example, pageable); + } + + @Override + @Transactional + public int modifyByCiCode(Long ciCode) { + return repository.updateInHitForMinCivBoard680(ciCode); + } + + @Override + @Transactional + public void saveBoard(BoardDto dto) { + MinCivBoard680 entity = null; + + // update 인 경우 + if(Checks.isNotEmpty(dto.getCiCode())) { + entity = repository.findById(dto.getCiCode()).orElseThrow(() -> new CustomBaseException(ErrorCode.DATA_NOT_FOUND)); + if(!entity.getCiPass().equals(passwordEncoder.encode(dto.getCiPass()))){ + throw new CustomBaseException(ErrorCode.MISMATCH_PASSWORD); + } + entity.setCiTitle(dto.getCiTitle()); + entity.setCiContents(dto.getCiContents()); + }else { + dto.setCiCode(repository.getCiCode()); + dto.setCiContentno(dto.getCiCode()); + if (Checks.isEmpty(dto.getCiRef()) || dto.getCiRef() == 0L) { + dto.setCiRef(dto.getCiCode()); + dto.setCiStep(0L); + dto.setCiRevel(0L); + } + dto.setCiPass(passwordEncoder.encode(dto.getCiPass())); + dto.setCiIp(CommUtil.getDeviceInfo().getIp()); + entity = mapstruct.toEntity(dto); + } + repository.save(entity); } } diff --git a/src/main/java/com/xit/core/constant/ErrorCode.java b/src/main/java/com/xit/core/constant/ErrorCode.java index 1e03213..b904670 100644 --- a/src/main/java/com/xit/core/constant/ErrorCode.java +++ b/src/main/java/com/xit/core/constant/ErrorCode.java @@ -77,6 +77,8 @@ public enum ErrorCode { FORBIDDEN(HttpStatus.FORBIDDEN, "FORBIDDEN"), INVALID_CODE(HttpStatus.BAD_REQUEST, "유효하지 않은 HttpStatus 상태 코드 입니다"), INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "INTERNAL_SERVER_ERROR"), + + MISMATCH_PASSWORD(HttpStatus.BAD_REQUEST, "비밀 번호가 일치하지 않습니다.") ; diff --git a/src/main/java/com/xit/core/util/CommUtil.java b/src/main/java/com/xit/core/util/CommUtil.java index 9494df7..9226261 100644 --- a/src/main/java/com/xit/core/util/CommUtil.java +++ b/src/main/java/com/xit/core/util/CommUtil.java @@ -8,6 +8,8 @@ import org.mozilla.universalchardet.UniversalDetector; import org.springframework.http.ResponseCookie; import org.springframework.mobile.device.Device; import org.springframework.mobile.device.DeviceUtils; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -392,6 +394,10 @@ public class CommUtil { return Long.toHexString(lDec).toUpperCase(); } + public static DeviceInfo getDeviceInfo() { + return getDeviceInfo(((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()); + } + /** * 접속 디바이스 정보 조회 * @param request HttpServletRequest