diff --git a/egovframe-template-simple-react-contribution/src/api/egovFetch.js b/egovframe-template-simple-react-contribution/src/api/egovFetch.js
index f634fb1..4ed6da9 100644
--- a/egovframe-template-simple-react-contribution/src/api/egovFetch.js
+++ b/egovframe-template-simple-react-contribution/src/api/egovFetch.js
@@ -29,65 +29,67 @@ export function requestFetch(url, requestOptions, handler, errorHandler) {
const accessToken = getLocalItem('accessToken');
const sessionUser = parseJwt(accessToken);
const sessionUserId = sessionUser?.id || null;
- const refreshToken = getLocalItem('refreshToken');
- if(sessionUserId != null){
- if( !requestOptions['headers'] ) requestOptions['headers']={}
- if( !requestOptions['headers']['Authorization'] ) requestOptions['headers']['Authorization']=null;
- requestOptions['headers']['Authorization'] = accessToken;
+
+ if(accessToken && new Date(sessionUser.exp*1000) < new Date()){
+ //만료된 토큰 재발급 절차 진행.
+ accessTokenRefresh(url, requestOptions, handler, errorHandler);
+ }else{
+ if(sessionUserId != null){
+ if( !requestOptions['headers'] ) requestOptions['headers']={}
+ if( !requestOptions['headers']['Authorization'] ) requestOptions['headers']['Authorization']=null;
+ requestOptions['headers']['Authorization'] = accessToken;
+ }
+
+ //CORS ISSUE 로 인한 조치 - origin 및 credentials 추가
+ // origin 추가
+ if (!requestOptions['origin']) {
+ requestOptions = { ...requestOptions, origin: SERVER_URL };
+ }
+ // credentials 추가
+ if (!requestOptions['credentials']) {
+ requestOptions = { ...requestOptions, credentials: 'include' };
+ }
+
+ fetch(SERVER_URL + url, requestOptions)
+ .then(response => {// response Stream. Not completion object
+ return response.json();
+ })
+ .then((resp) => {
+ if (Number(resp.resultCode) === Number(CODE.RCV_ERROR_AUTH)) {
+ alert("로그인이 해제되었습니다.")
+ window.location.href = "/login"
+ }else{
+ return resp;
+ }
+ })
+ .then((resp) => {
+ console.groupCollapsed("requestFetch.then()");
+ console.log("requestFetch [response] ", resp);
+ if (typeof handler === 'function') {
+ handler(resp);
+ } else {
+ console.log('egov fetch handler not assigned!');
+ }
+ console.groupEnd("requestFetch.then()");
+ })
+ .catch(error => {
+ console.error('There was an error!', error);
+ if (error === 'TypeError: Failed to fetch') {
+ alert("서버와의 연결이 원활하지 않습니다. 서버를 확인하세요.");
+ }
+
+ if (typeof errorHandler === 'function') {
+ errorHandler(error);
+ } else {
+ console.error('egov error handler not assigned!');
+ alert("ERR : " + error.message);
+ }
+ })
+ .finally(() => {
+ console.log("requestFetch finally end");
+ console.groupEnd("requestFetch");
+ });
}
-
- //CORS ISSUE 로 인한 조치 - origin 및 credentials 추가
- // origin 추가
- if (!requestOptions['origin']) {
- requestOptions = { ...requestOptions, origin: SERVER_URL };
- }
- // credentials 추가
- if (!requestOptions['credentials']) {
- requestOptions = { ...requestOptions, credentials: 'include' };
- }
-
- fetch(SERVER_URL + url, requestOptions)
- .then(response => {// response Stream. Not completion object
- //console.log("requestFetch [Response Stream] ", response);
- return response.json();
- })
- .then((resp) => {
- if (Number(resp.resultCode) === Number(CODE.RCV_ERROR_AUTH)) {
- //accessToken 갱신 요청
- accessTokenRefresh(url, requestOptions, handler, errorHandler);
- return resp;
- } else {
- return resp;
- }
- })
- .then((resp) => {
- console.groupCollapsed("requestFetch.then()");
- console.log("requestFetch [response] ", resp);
- if (typeof handler === 'function') {
- handler(resp);
- } else {
- console.log('egov fetch handler not assigned!');
- }
- console.groupEnd("requestFetch.then()");
- })
- .catch(error => {
- console.error('There was an error!', error);
- if (error === 'TypeError: Failed to fetch') {
- alert("서버와의 연결이 원활하지 않습니다. 서버를 확인하세요.");
- }
-
- if (typeof errorHandler === 'function') {
- errorHandler(error);
- } else {
- console.error('egov error handler not assigned!');
- alert("ERR : " + error.message);
- }
- })
- .finally(() => {
- console.log("requestFetch finally end");
- console.groupEnd("requestFetch");
- });
-
}
function accessTokenRefresh(url, requestOptions, handler, errorHandler){
diff --git a/egovframe-template-simple-react-contribution/src/pages/standardCode/list/FavoriteIcon.jsx b/egovframe-template-simple-react-contribution/src/pages/standardCode/list/FavoriteIcon.jsx
new file mode 100644
index 0000000..4a59686
--- /dev/null
+++ b/egovframe-template-simple-react-contribution/src/pages/standardCode/list/FavoriteIcon.jsx
@@ -0,0 +1,46 @@
+
+import React, {useState} from "react";
+import {AiFillStar} from "react-icons/ai";
+import {getLocalItem} from "utils/storage";
+import * as EgovNet from "../../../api/egovFetch";
+
+function FavoriteIcon({item}){
+
+ const [favoriteChk, setFavoriteChk] = useState(item.favoriteChk);
+
+ function favoriteStateChange(groupSeq, checked){
+ EgovNet.requestFetch(
+ '/standardCode/document-favorite',
+ {
+ method: "POST",
+ headers: {
+ 'Content-type': 'application/json',
+ },
+ body:JSON.stringify({groupSeq: groupSeq, active: checked})
+ },
+ (resp) => {
+
+ },
+ function (resp) {
+ console.log("err response : ", resp);
+ }
+ );
+ }
+
+ return (
+
{
+ const accessToken = getLocalItem('accessToken')
+ if(accessToken) {
+ favoriteStateChange(item.groupSeq, !favoriteChk)
+ setFavoriteChk(!favoriteChk)
+ }else{
+ alert("로그인 후 이용 가능한 서비스 입니다.")
+ }
+ }}>
+
+
+ );
+}
+
+export default FavoriteIcon;
\ No newline at end of file
diff --git a/egovframe-template-simple-react-contribution/src/pages/standardCode/list/StandardCodeList.jsx b/egovframe-template-simple-react-contribution/src/pages/standardCode/list/StandardCodeList.jsx
index f59d217..7e1c1cf 100644
--- a/egovframe-template-simple-react-contribution/src/pages/standardCode/list/StandardCodeList.jsx
+++ b/egovframe-template-simple-react-contribution/src/pages/standardCode/list/StandardCodeList.jsx
@@ -1,8 +1,7 @@
import React from 'react';
-
-import {AiFillStar} from "react-icons/ai";
import Col from "react-bootstrap/Col";
import Row from "react-bootstrap/Row";
+import FavoriteIcon from "./FavoriteIcon";
function StandardCodeList({listData, filterData}) {
@@ -76,7 +75,7 @@ function StandardCodeList({listData, filterData}) {
})}
-
+
)
})}
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/entity/LoginVO.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/entity/LoginVO.java
index b3eb27c..52b7c3d 100644
--- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/entity/LoginVO.java
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/auth/entity/LoginVO.java
@@ -34,6 +34,9 @@ public class LoginVO implements Serializable{
*
*/
private static final long serialVersionUID = -8274004534207618049L;
+
+ @Schema(description = "사용자 번호")
+ private Integer userSeq;
@Schema(description = "아이디")
@Pattern(regexp = "^[a-zA-Z]{1}[a-zA-Z0-9_]{4,11}$")
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/JwtAuthenticationFilter.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/JwtAuthenticationFilter.java
index 0615647..00287f9 100644
--- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/JwtAuthenticationFilter.java
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/config/jwt/JwtAuthenticationFilter.java
@@ -67,6 +67,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
LoginVO loginVO = new LoginVO();
if( verificationFlag ){
logger.debug("jwtToken validated");
+ loginVO.setUserSeq(Integer.parseInt(jwtTokenUtil.getUserSeqFromToken(jwtToken)));
loginVO.setId(id);
loginVO.setUserSe( jwtTokenUtil.getUserSeFromToken(jwtToken) );
// loginVO.setUniqId( jwtTokenUtil.getInfoFromToken("uniqId",jwtToken) );
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/StandardCodeController.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/StandardCodeController.java
index 8bbb018..e1bf2bb 100644
--- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/StandardCodeController.java
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/StandardCodeController.java
@@ -6,6 +6,7 @@ import com.dbnt.kcscbackend.config.common.ResponseCode;
import com.dbnt.kcscbackend.config.common.ResultVO;
import com.dbnt.kcscbackend.standardCode.entity.TnDocumentCodeList;
import com.dbnt.kcscbackend.standardCode.entity.TnDocumentContent;
+import com.dbnt.kcscbackend.standardCode.entity.TnDocumentFavorites;
import com.dbnt.kcscbackend.standardCode.entity.TnDocumentInfo;
import com.dbnt.kcscbackend.standardCode.service.StandardCodeService;
import com.dbnt.kcscbackend.standardCode.service.StandardCodeVO;
@@ -152,9 +153,9 @@ public class StandardCodeController extends BaseController {
Map resultMap = new HashMap<>();
tnDocumentInfo.makeListCode();
+ tnDocumentInfo.setUserSeq(user.getUserSeq());
resultMap.put("resultList", standardCodeService.selectStandardCodeList(tnDocumentInfo));
resultMap.put("resultCnt", standardCodeService.selectStandardCodeListCnt(tnDocumentInfo));
- resultMap.put("user", user);
resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage());
@@ -184,6 +185,34 @@ public class StandardCodeController extends BaseController {
return resultVO;
}
+ @Operation(
+ summary = "건설기준코드 즐겨찾기 추가, 삭제",
+ description = "건설기준코드 즐겨찾기 추가, 삭제",
+ tags = {"StandardCodeController"}
+ )
+ @ApiResponses(value = {
+ @ApiResponse(responseCode = "200", description = "수정 성공"),
+ @ApiResponse(responseCode = "403", description = "인가된 사용자가 아님")
+ })
+ @PostMapping(value = "/document-favorite")
+ public ResultVO setDocumentFavorite(@RequestBody TnDocumentFavorites favorites, @AuthenticationPrincipal LoginVO loginUser) throws Exception {
+ ResultVO resultVO = new ResultVO();
+ if(favorites.getActive()==null){
+ resultVO.setResultCode(ResponseCode.SAVE_ERROR.getCode());
+ resultVO.setResultMessage(ResponseCode.SAVE_ERROR.getMessage());
+ return resultVO;
+ }
+
+ if(favorites.getActive()){
+ standardCodeService.saveFavorites(loginUser.getUserSeq(), favorites.getGroupSeq());
+ }else{
+ standardCodeService.deleteFavorites(loginUser.getUserSeq(), favorites.getGroupSeq());
+ }
+ resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
+ resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage());
+ return resultVO;
+ }
+
@Operation(
summary = "건설기준코드 개정이력 조회",
description = "건설기준코드 개정이력 조회",
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/entity/TnDocumentCodeList.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/entity/TnDocumentCodeList.java
index 04e2bd9..e2974ab 100644
--- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/entity/TnDocumentCodeList.java
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/entity/TnDocumentCodeList.java
@@ -45,6 +45,8 @@ public class TnDocumentCodeList {
@Transient
private Integer remarkCnt;
@Transient
+ private Boolean favoriteChk;
+ @Transient
private List historyList;
}
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/entity/TnDocumentFavorites.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/entity/TnDocumentFavorites.java
new file mode 100644
index 0000000..60deec4
--- /dev/null
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/entity/TnDocumentFavorites.java
@@ -0,0 +1,40 @@
+package com.dbnt.kcscbackend.standardCode.entity;
+
+import lombok.*;
+import org.hibernate.annotations.DynamicInsert;
+import org.hibernate.annotations.DynamicUpdate;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+@Getter
+@Setter
+@Entity
+@NoArgsConstructor
+@DynamicInsert
+@DynamicUpdate
+@Table(name = "tn_document_favorites")
+@IdClass(TnDocumentFavorites.TnDocumentFavoritesId.class)
+public class TnDocumentFavorites {
+ @Id
+ @Column(name = "user_seq")
+ private Integer userSeq;
+ @Id
+ @Column(name = "group_seq")
+ private Integer groupSeq;
+
+ @Transient
+ private Boolean active;
+
+
+ @Embeddable
+ @Data
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class TnDocumentFavoritesId implements Serializable {
+ private Integer userSeq;
+ private Integer groupSeq;
+ }
+}
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/entity/TnDocumentInfo.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/entity/TnDocumentInfo.java
index bd15fc0..8acc2d3 100644
--- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/entity/TnDocumentInfo.java
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/entity/TnDocumentInfo.java
@@ -100,6 +100,8 @@ public class TnDocumentInfo {
private String category2 = "";
@Transient
private String category3 = "";
+ @Transient
+ private Integer userSeq;
@JsonIgnore
public void makeListCode(){
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/repository/TnDocumentFavoritesRepository.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/repository/TnDocumentFavoritesRepository.java
new file mode 100644
index 0000000..5f40eeb
--- /dev/null
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/repository/TnDocumentFavoritesRepository.java
@@ -0,0 +1,8 @@
+package com.dbnt.kcscbackend.standardCode.repository;
+
+import com.dbnt.kcscbackend.standardCode.entity.TnDocumentFavorites;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+
+public interface TnDocumentFavoritesRepository extends JpaRepository {
+}
diff --git a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/service/StandardCodeService.java b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/service/StandardCodeService.java
index 96ff80f..a0fc817 100644
--- a/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/service/StandardCodeService.java
+++ b/kcsc-back-end/src/main/java/com/dbnt/kcscbackend/standardCode/service/StandardCodeService.java
@@ -1,11 +1,9 @@
package com.dbnt.kcscbackend.standardCode.service;
-import com.dbnt.kcscbackend.standardCode.entity.TnDocumentCodeList;
-import com.dbnt.kcscbackend.standardCode.entity.TnDocumentContent;
-import com.dbnt.kcscbackend.standardCode.entity.TnDocumentGroup;
-import com.dbnt.kcscbackend.standardCode.entity.TnDocumentInfo;
+import com.dbnt.kcscbackend.standardCode.entity.*;
import com.dbnt.kcscbackend.standardCode.mapper.StandardCodeMapper;
import com.dbnt.kcscbackend.standardCode.repository.TnDocumentContentRepository;
+import com.dbnt.kcscbackend.standardCode.repository.TnDocumentFavoritesRepository;
import com.dbnt.kcscbackend.standardCode.repository.TnDocumentGroupRepository;
import com.dbnt.kcscbackend.standardCode.repository.TnDocumentInfoRepository;
import lombok.RequiredArgsConstructor;
@@ -23,6 +21,7 @@ public class StandardCodeService extends EgovAbstractServiceImpl {
private final TnDocumentGroupRepository tnDocumentGroupRepository;
private final TnDocumentContentRepository tnDocumentContentRepository;
private final TnDocumentInfoRepository tnDocumentInfoRepository;
+ private final TnDocumentFavoritesRepository favoritesRepository;
private final StandardCodeMapper standardCodeMapper;
@Transactional
@@ -74,4 +73,15 @@ public class StandardCodeService extends EgovAbstractServiceImpl {
public List selectTnDocumentGroupToGroupFullCdLike(String groupFullCd) {
return tnDocumentGroupRepository.findByGroupFullCdLike(groupFullCd+"__");
}
+
+ public void saveFavorites(Integer userSeq, Integer groupSeq){
+ TnDocumentFavorites favorites = new TnDocumentFavorites();
+ favorites.setUserSeq(userSeq);
+ favorites.setGroupSeq(groupSeq);
+ favoritesRepository.save(favorites);
+ }
+
+ public void deleteFavorites(Integer userSeq, Integer groupSeq){
+ favoritesRepository.deleteById(new TnDocumentFavorites.TnDocumentFavoritesId(userSeq, groupSeq));
+ }
}
diff --git a/kcsc-back-end/src/main/resources/mybatisMapper/StandardCodeMapper.xml b/kcsc-back-end/src/main/resources/mybatisMapper/StandardCodeMapper.xml
index 994679d..7e8acab 100644
--- a/kcsc-back-end/src/main/resources/mybatisMapper/StandardCodeMapper.xml
+++ b/kcsc-back-end/src/main/resources/mybatisMapper/StandardCodeMapper.xml
@@ -35,11 +35,20 @@
c.rvsn_remark ,
c.kcsc_cd,
tdi.doc_file_grp_id,
- c.group_seq
+ c.group_seq,
+ tdf.user_seq is not null as favoriteChk
from tn_document_group a
inner join tn_document_group b on a.group_seq = b.parent_group_seq
inner join tn_document_group c on b.group_seq = c.parent_group_seq
left join tn_document_info tdi on c.group_seq = tdi.group_seq
+ left join tn_document_favorites tdf
+ on c.group_seq = tdf.group_seq
+
+ and 1=0
+
+
+ and tdf.user_seq = #{userSeq}
+
order by c.kcsc_cd