스팸단어 체크
This commit is contained in:
parent
7caaa99ae9
commit
b5c1cba2c3
4
pom.xml
4
pom.xml
@ -166,6 +166,10 @@
|
||||
<version>1.4.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
@ -23,9 +23,9 @@ class MjonAgentSDatabaseConfig {
|
||||
// A database DataSource
|
||||
@Bean(AGENT_S_DATA_SOURCE)
|
||||
@ConfigurationProperties(prefix = "spring.mjagent.server.datasource")
|
||||
public DataSource CommuteDataSource() {
|
||||
public DataSource MjagentServerSource() {
|
||||
return DataSourceBuilder.create()
|
||||
// .type(HikariDataSource.class)
|
||||
.type(com.zaxxer.hikari.HikariDataSource.class) // HikariDataSource를 명시적으로 사용
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@ -7,8 +7,8 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
@Mapper
|
||||
public interface CodeDetailMapper {
|
||||
List<CodeDetailVO> findByGroupId(String codeGroupId);
|
||||
CodeDetailVO findById(String codeId);
|
||||
CodeDetailVO findById(String codeGroupId, String codeId);
|
||||
void insert(CodeDetailVO codeDetailVO);
|
||||
void update(CodeDetailVO codeDetailVO);
|
||||
void delete(String codeId);
|
||||
void delete(String codeGroupId, String codeId);
|
||||
}
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
package com.itn.admin.itn.code.mapper.domain;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.*;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CodeDetailVO {
|
||||
|
||||
@ -12,14 +12,14 @@ public interface CodeDetailService {
|
||||
List<CodeDetailVO> getDetailsByGroupId(String codeGroupId);
|
||||
|
||||
// 특정 코드 상세를 ID로 가져오는 메서드
|
||||
CodeDetailVO getCodeDetailById(String codeId);
|
||||
CodeDetailVO getCodeDetailById(String codeGroupId, String codeId);
|
||||
|
||||
// 코드 상세 추가 메서드
|
||||
RestResponse addCodeDetail(CodeDetailVO codeDetail);
|
||||
|
||||
// 코드 상세 수정 메서드
|
||||
void updateCodeDetail(CodeDetailVO codeDetail);
|
||||
RestResponse updateCodeDetail(CodeDetailVO codeDetail);
|
||||
|
||||
// 코드 상세 삭제 메서드
|
||||
void deleteCodeDetail(String codeId);
|
||||
void deleteCodeDetail(String codeGroupId, String codeId);
|
||||
}
|
||||
|
||||
@ -2,14 +2,17 @@ package com.itn.admin.itn.code.server.impl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.itn.admin.cmn.config.SecurityUtil;
|
||||
import com.itn.admin.cmn.msg.RestResponse;
|
||||
import com.itn.admin.itn.code.mapper.CodeDetailMapper;
|
||||
import com.itn.admin.itn.code.mapper.domain.CodeDetailVO;
|
||||
import com.itn.admin.itn.code.server.CodeDetailService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
public class CodeDetailServiceImpl implements CodeDetailService {
|
||||
|
||||
@ -22,23 +25,51 @@ public class CodeDetailServiceImpl implements CodeDetailService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeDetailVO getCodeDetailById(String codeId) {
|
||||
return codeDetailMapper.findById(codeId);
|
||||
public CodeDetailVO getCodeDetailById(String codeGroupId, String codeId) {
|
||||
CodeDetailVO codeDetailVO = new CodeDetailVO();
|
||||
return codeDetailMapper.findById(codeGroupId, codeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResponse addCodeDetail(CodeDetailVO codeDetail) {
|
||||
codeDetailMapper.insert(codeDetail);
|
||||
|
||||
// 현재 인증된 사용자 정보 가져오기
|
||||
String userId = SecurityUtil.getCurrentUserId();
|
||||
if (userId == null) {
|
||||
log.warn("Failed to retrieve current user ID.");
|
||||
throw new IllegalStateException("Current user ID is not available");
|
||||
}
|
||||
log.info("Updating by user: [{}]", userId);
|
||||
|
||||
codeDetail.setFrstRegisterId(userId);
|
||||
codeDetail.setLastUpdusrId(userId);
|
||||
try {
|
||||
codeDetailMapper.insert(codeDetail);
|
||||
}catch (Exception e) {
|
||||
return new RestResponse(HttpStatus.BAD_REQUEST, "코드 ID:"+ codeDetail.getCodeId() + " 를 확인해주세요. \n이미 등록되어 있을 수 있습니다." , codeDetail.getCodeName());
|
||||
}
|
||||
|
||||
return new RestResponse(HttpStatus.OK, "등록되었습니다", codeDetail.getCodeName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCodeDetail(CodeDetailVO codeDetail) {
|
||||
public RestResponse updateCodeDetail(CodeDetailVO codeDetail) {
|
||||
|
||||
// 현재 인증된 사용자 정보 가져오기
|
||||
String userId = SecurityUtil.getCurrentUserId();
|
||||
if (userId == null) {
|
||||
log.warn("Failed to retrieve current user ID.");
|
||||
throw new IllegalStateException("Current user ID is not available");
|
||||
}
|
||||
log.info("Updating by user: [{}]", userId);
|
||||
|
||||
codeDetail.setLastUpdusrId(userId);
|
||||
codeDetailMapper.update(codeDetail);
|
||||
return new RestResponse(HttpStatus.OK, "등록되었습니다", codeDetail.getCodeName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteCodeDetail(String codeId) {
|
||||
codeDetailMapper.delete(codeId);
|
||||
public void deleteCodeDetail(String codeGroupId, String codeId){
|
||||
codeDetailMapper.delete(codeGroupId, codeId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,13 +3,16 @@ package com.itn.admin.itn.code.web;
|
||||
import com.itn.admin.cmn.msg.RestResponse;
|
||||
import com.itn.admin.itn.code.mapper.domain.CodeDetailVO;
|
||||
import com.itn.admin.itn.code.server.CodeDetailService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/code-details") // URL 경로를 '/api/code-details'로 변경
|
||||
public class CodeDetailRestController {
|
||||
@ -24,9 +27,9 @@ public class CodeDetailRestController {
|
||||
}
|
||||
|
||||
// 특정 코드 상세를 ID로 가져오는 메서드
|
||||
@GetMapping("/detail/{codeId}")
|
||||
public CodeDetailVO getCodeDetailById(@PathVariable String codeId) {
|
||||
return codeDetailService.getCodeDetailById(codeId);
|
||||
@GetMapping("/detail/{codeGroupId}/{codeId}")
|
||||
public CodeDetailVO getCodeDetailById(@PathVariable String codeGroupId,@PathVariable String codeId) {
|
||||
return codeDetailService.getCodeDetailById(codeGroupId, codeId);
|
||||
}
|
||||
|
||||
// 코드 상세 추가 메서드
|
||||
@ -37,14 +40,16 @@ public class CodeDetailRestController {
|
||||
|
||||
// 코드 상세 수정 메서드
|
||||
@PutMapping("/detail/{codeId}")
|
||||
public void updateCodeDetail(@PathVariable String codeId, @RequestBody CodeDetailVO codeDetail) {
|
||||
codeDetail.setCodeId(codeId);
|
||||
codeDetailService.updateCodeDetail(codeDetail);
|
||||
public ResponseEntity<RestResponse> updateCodeDetail(@PathVariable String codeId, @RequestBody CodeDetailVO codeDetail) {
|
||||
// log.info("codeDetail :: [{}]", codeDetail.toString());
|
||||
|
||||
return ResponseEntity.ok().body(codeDetailService.updateCodeDetail(codeDetail));
|
||||
|
||||
}
|
||||
|
||||
// 코드 상세 삭제 메서드
|
||||
@DeleteMapping("/detail/{codeId}")
|
||||
public void deleteCodeDetail(@PathVariable String codeId) {
|
||||
codeDetailService.deleteCodeDetail(codeId);
|
||||
@DeleteMapping("/detail/{codeGroupId}/{codeId}")
|
||||
public void deleteCodeDetail(@PathVariable String codeGroupId,@PathVariable String codeId) {
|
||||
codeDetailService.deleteCodeDetail(codeGroupId, codeId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,4 +20,8 @@ public interface SpamMapper {
|
||||
List<SpamVO> getSpamList(SpamVO spamVO);
|
||||
|
||||
int getTotalRecordCount();
|
||||
|
||||
SpamVO findById(String spamId);
|
||||
|
||||
void updateByKeywordsAndChcKeywordsWhereSpamId(SpamVO spamVO);
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.itn.admin.itn.mjon.spam.mapper.domain;
|
||||
|
||||
import com.itn.admin.cmn.vo.CmnVO;
|
||||
import com.itn.admin.itn.code.mapper.domain.CodeDetailVO;
|
||||
import lombok.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
@ -30,9 +31,9 @@ public class SpamVO extends CmnVO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int spamId; // 스팸 ID
|
||||
private String msgGroupId; // 문자그룹ID
|
||||
private String smsTxt; // 문자내용
|
||||
private String spamRsn; // 스팸사유
|
||||
private String spamRsnCode01; // 스팸코드01
|
||||
private String spamRsnCode02; // 스팸코드02
|
||||
private String keywords; // 문자에 포함된 단어
|
||||
private String chcKeywords; // 스팸에 해당하는 단어
|
||||
private LocalDateTime timestamp; // 요청 시간
|
||||
@ -43,6 +44,11 @@ public class SpamVO extends CmnVO implements Serializable {
|
||||
private LocalDateTime lastUpdtPnttm; // 최종수정일자
|
||||
|
||||
|
||||
private List<CodeDetailVO> CodeDetailList; // 최종수정일자
|
||||
|
||||
|
||||
|
||||
// spam_keywords TB 외 필드들
|
||||
private List<String> keywordList; // 키워드 리스트
|
||||
private List<String> chcKeywordList; // 키워드 리스트
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package com.itn.admin.itn.mjon.spam.service;
|
||||
|
||||
import com.itn.admin.cmn.msg.RestResponse;
|
||||
import com.itn.admin.itn.code.mapper.domain.CodeDetailVO;
|
||||
import com.itn.admin.itn.mjon.spam.mapper.domain.SpamVO;
|
||||
|
||||
import java.util.Map;
|
||||
@ -13,4 +15,8 @@ public interface SpamService {
|
||||
void analyze();
|
||||
|
||||
Map<String, Object> getSpamList(SpamVO spamVO);
|
||||
|
||||
RestResponse updateKeyword(String spamId, String word);
|
||||
|
||||
RestResponse updateChcKeyword(String spamId, String word);
|
||||
}
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
package com.itn.admin.itn.mjon.spam.service.impl;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.itn.admin.cmn.msg.RestResponse;
|
||||
import com.itn.admin.itn.code.mapper.domain.CodeDetailVO;
|
||||
import com.itn.admin.itn.code.server.CodeDetailService;
|
||||
import com.itn.admin.itn.mjon.spam.mapper.SpamMapper;
|
||||
import com.itn.admin.itn.mjon.spam.mapper.domain.SpamVO;
|
||||
import com.itn.admin.itn.mjon.spam.service.SpamService;
|
||||
import jakarta.servlet.ServletOutputStream;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.*;
|
||||
@ -11,6 +15,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@ -20,11 +25,13 @@ public class SpamServiceImpl implements SpamService {
|
||||
@Autowired
|
||||
SpamMapper spamMapper;
|
||||
|
||||
@Autowired
|
||||
private CodeDetailService codeDetailService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
|
||||
|
||||
final static private String PYTHON_ANALYZE_URL= "http://192.168.0.78:5000/word_analyze";
|
||||
|
||||
public SpamServiceImpl(RestTemplate restTemplate) {
|
||||
@ -40,7 +47,6 @@ public class SpamServiceImpl implements SpamService {
|
||||
|
||||
map.put("spamList", spamList);
|
||||
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
@ -114,19 +120,90 @@ public class SpamServiceImpl implements SpamService {
|
||||
|
||||
List<SpamVO> spamList = spamMapper.getSpamList(spamVO);
|
||||
|
||||
|
||||
// 키워드를 버튼용 배열로 변환
|
||||
for (SpamVO spam : spamList) {
|
||||
if (spam.getKeywords() != null) {
|
||||
spam.setKeywordList(Arrays.asList(spam.getKeywords().split(", ")));
|
||||
}
|
||||
if (spam.getChcKeywords() != null) {
|
||||
spam.setChcKeywordList(Arrays.asList(spam.getChcKeywords().split(", ")));
|
||||
}
|
||||
}
|
||||
|
||||
List<CodeDetailVO> rsnCode02List = new ArrayList<>();
|
||||
// 키워드를 버튼용 배열로 변환
|
||||
for (SpamVO spam : spamList) {
|
||||
if (spam.getSpamRsnCode01() != null) {
|
||||
spam.setCodeDetailList(codeDetailService.getDetailsByGroupId("SPAM"+spam.getSpamRsnCode01()));
|
||||
}
|
||||
}
|
||||
|
||||
List<CodeDetailVO> rsnCode01List = codeDetailService.getDetailsByGroupId("SPAM");
|
||||
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
resultMap.put("spamList", spamList);
|
||||
resultMap.put("totalRecordCount", totalRecordCount);
|
||||
resultMap.put("totalPageCount", spamVO.getTotalPageCount());
|
||||
|
||||
resultMap.put("rsnCode01List", rsnCode01List);
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResponse updateChcKeyword(String spamId, String word) {
|
||||
SpamVO spamVO = spamMapper.findById(spamId);
|
||||
|
||||
spamVO.setKeywords(removeString(spamVO.getKeywords(),word));
|
||||
spamVO.setChcKeywords(addString(spamVO.getChcKeywords(),word));
|
||||
|
||||
spamMapper.updateByKeywordsAndChcKeywordsWhereSpamId(spamVO);
|
||||
|
||||
return new RestResponse(HttpStatus.OK, word+" 단어가 선택되었습니다.","");
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestResponse updateKeyword(String spamId, String word) {
|
||||
SpamVO spamVO = spamMapper.findById(spamId);
|
||||
|
||||
spamVO.setChcKeywords(removeString(spamVO.getChcKeywords(),word));
|
||||
spamVO.setKeywords(addString(spamVO.getKeywords(),word));
|
||||
|
||||
|
||||
spamMapper.updateByKeywordsAndChcKeywordsWhereSpamId(spamVO);
|
||||
|
||||
return new RestResponse(HttpStatus.OK, word+" 단어가 취소되었습니다.","");
|
||||
}
|
||||
|
||||
|
||||
private String removeString(String keywords, String word) {
|
||||
String[] keywordArray = keywords.split(", ");
|
||||
return Arrays.stream(keywordArray)
|
||||
.filter(s -> !s.equals(word))
|
||||
.collect(Collectors.joining(", "));
|
||||
|
||||
|
||||
}
|
||||
|
||||
private String addString(String keywords, String word) {
|
||||
|
||||
if (keywords == null) {
|
||||
keywords = "";
|
||||
}
|
||||
|
||||
String[] keywordArray = keywords.split(", ");
|
||||
boolean wordExists = Arrays.stream(keywordArray).anyMatch(kw -> kw.equals(word));
|
||||
if (!wordExists) {
|
||||
// keywords 문자열이 비어있지 않은 경우, 쉼표를 추가한 후 새로운 단어를 추가합니다.
|
||||
if (!keywords.isEmpty()) {
|
||||
keywords += ", " + word;
|
||||
} else {
|
||||
// keywords가 비어있으면, 쉼표 없이 새로운 단어를 추가합니다.
|
||||
keywords = word;
|
||||
}
|
||||
}
|
||||
|
||||
return keywords;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,15 @@
|
||||
package com.itn.admin.itn.mjon.spam.web;
|
||||
|
||||
import com.itn.admin.cmn.msg.RestResponse;
|
||||
import com.itn.admin.itn.code.mapper.domain.CodeDetailVO;
|
||||
import com.itn.admin.itn.mjon.spam.service.SpamService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Slf4j
|
||||
@ -21,15 +26,21 @@ public class RestSpamController {
|
||||
|
||||
@GetMapping(value = "/mjon/spam/analyze")
|
||||
public void analyze(Model model) {
|
||||
|
||||
|
||||
spamService.analyze();
|
||||
}
|
||||
|
||||
// 키워드 -> 핵심키워드 :: keywords -> chc_keywords
|
||||
@PutMapping("/mjon/spam/chcKeyword/{spamId}/{word}")
|
||||
public ResponseEntity<RestResponse> updateChcKeyword(@PathVariable String spamId, @PathVariable String word) {
|
||||
return ResponseEntity.ok().body(spamService.updateChcKeyword(spamId, word));
|
||||
}
|
||||
|
||||
|
||||
// 핵심키워드 -> 키워드 :: chc_keywords -> keywords
|
||||
@PutMapping("/mjon/spam/keyword/{spamId}/{word}")
|
||||
public ResponseEntity<RestResponse> updateKeyword(@PathVariable String spamId, @PathVariable String word) {
|
||||
return ResponseEntity.ok().body(spamService.updateKeyword(spamId, word));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -30,9 +30,15 @@ public class SpamController {
|
||||
|
||||
model.addAttribute("spamList", map.get("spamList"));
|
||||
model.addAttribute("pagingVO", spamVO);
|
||||
model.addAttribute("rsnCode01List", map.get("rsnCode01List"));
|
||||
|
||||
return "mjon/spam/select";
|
||||
}
|
||||
@GetMapping(value = "/mjon/spam/chk")
|
||||
public String chk(@ModelAttribute("spamVO") SpamVO spamVO, Model model) {
|
||||
|
||||
return "mjon/spam/chk";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -32,6 +32,7 @@ spring.main.datasource.password=itntest123
|
||||
#
|
||||
spring.commute.datasource.driverClassName=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
|
||||
spring.commute.datasource.jdbc-url=jdbc:log4jdbc:mysql://192.168.0.200:3312/biostar2_ac?serverTimezone=Asia/Seoul
|
||||
#spring.commute.datasource.jdbc-url=jdbc:log4jdbc:mysql://192.168.0.30:3312/biostar2_ac?serverTimezone=Asia/Seoul
|
||||
spring.commute.datasource.username=root
|
||||
spring.commute.datasource.password=itntest!
|
||||
|
||||
@ -54,7 +55,8 @@ spring.mjagent.server.datasource.driverClassName=net.sf.log4jdbc.sql.jdbcapi.Dri
|
||||
spring.mjagent.server.datasource.jdbc-url=jdbc:log4jdbc:mysql://119.193.215.98:3306/mjon_agent_back?serverTimezone=Asia/Seoul
|
||||
spring.mjagent.server.datasource.username=mjonUr_agent
|
||||
spring.mjagent.server.datasource.password=mjagent123$
|
||||
|
||||
spring.mjagent.server.datasource.hikari.minimum-idle=2
|
||||
spring.mjagent.server.datasource.hikari.maximum-pool-size=4
|
||||
|
||||
|
||||
|
||||
|
||||
@ -60,6 +60,7 @@
|
||||
MUNJAON_MSG
|
||||
WHERE SEND_STATUS != 1000
|
||||
and MSG_TYPE = #{msgType}
|
||||
and MESSAGE LIKE CONCAT(#{message}, '%')
|
||||
</select>
|
||||
|
||||
<!-- 리포트할때 현재 데이터가 LOG 테이블에 이동됐는지 확인 -->
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
<!-- 특정 코드 상세를 ID로 조회하는 쿼리 -->
|
||||
<select id="findById" parameterType="String" resultType="codeDetailVO">
|
||||
SELECT * FROM common_code_detail WHERE code_id = #{codeId}
|
||||
SELECT * FROM common_code_detail WHERE code_id = #{codeId} AND code_group_id = #{codeGroupId}
|
||||
</select>
|
||||
|
||||
<!-- 코드 상세를 추가하는 쿼리 -->
|
||||
@ -35,6 +35,6 @@
|
||||
|
||||
<!-- 코드 상세를 삭제하는 쿼리 -->
|
||||
<delete id="delete" parameterType="String">
|
||||
DELETE FROM common_code_detail WHERE code_id = #{codeId}
|
||||
DELETE FROM common_code_detail WHERE code_id = #{codeId} AND code_group_id = #{codeGroupId}
|
||||
</delete>
|
||||
</mapper>
|
||||
@ -12,9 +12,9 @@
|
||||
<select id="getSpamList" parameterType="spamVO" resultType="SpamVO">
|
||||
SELECT
|
||||
SPAM_ID,
|
||||
MSG_GROUP_ID,
|
||||
SMS_TXT,
|
||||
SPAM_RSN,
|
||||
SPAM_RSN_CODE_01,
|
||||
SPAM_RSN_CODE_02,
|
||||
KEYWORDS,
|
||||
CHC_KEYWORDS,
|
||||
TIMESTAMP,
|
||||
@ -25,6 +25,7 @@
|
||||
LAST_UPDT_PNTTM
|
||||
FROM
|
||||
spam_keywords
|
||||
/*where chc_keywords is null*/
|
||||
ORDER BY
|
||||
SPAM_ID
|
||||
LIMIT #{limit} OFFSET #{offset}
|
||||
@ -35,9 +36,9 @@
|
||||
<select id="getList" parameterType="spamVO" resultType="spamVO">
|
||||
SELECT
|
||||
SPAM_ID,
|
||||
MSG_GROUP_ID,
|
||||
SMS_TXT,
|
||||
SPAM_RSN,
|
||||
SPAM_RSN_CODE_01,
|
||||
SPAM_RSN_CODE_02,
|
||||
KEYWORDS,
|
||||
CHC_KEYWORDS,
|
||||
TIMESTAMP,
|
||||
@ -73,9 +74,9 @@
|
||||
<select id="getListWhereKeywordsIsNull" parameterType="spamVO" resultType="spamVO">
|
||||
SELECT
|
||||
SPAM_ID,
|
||||
MSG_GROUP_ID,
|
||||
SMS_TXT,
|
||||
SPAM_RSN,
|
||||
SPAM_RSN_CODE_01,
|
||||
SPAM_RSN_CODE_02,
|
||||
KEYWORDS,
|
||||
CHC_KEYWORDS,
|
||||
TIMESTAMP,
|
||||
@ -90,10 +91,52 @@
|
||||
KEYWORDS IS NULL
|
||||
</select>
|
||||
|
||||
<select id="findById" parameterType="String" resultType="spamVO">
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
spam_keywords
|
||||
WHERE
|
||||
spam_id = #{spamId}
|
||||
</select>
|
||||
|
||||
<update id="update">
|
||||
UPDATE spam_keywords
|
||||
SET keywords = #{keywords}
|
||||
WHERE spam_id = #{spamId}
|
||||
</update>
|
||||
|
||||
<!-- 정확히 일치하는 단어와 그 개수를 검색하는 쿼리 -->
|
||||
<select id="selectByExactWordsWithCount" resultType="map">
|
||||
SELECT
|
||||
*,
|
||||
(
|
||||
<foreach item="word" index="index" collection="words" separator="+">
|
||||
CASE WHEN FIND_IN_SET(#{word}, REPLACE(chc_keywords, ', ', ',')) THEN 1 ELSE 0 END
|
||||
</foreach>
|
||||
) AS match_count,
|
||||
CONCAT(
|
||||
<foreach item="word" index="index" collection="words" separator=", ">
|
||||
IF(FIND_IN_SET(#{word}, REPLACE(chc_keywords, ', ', ',')), #{word}, NULL)
|
||||
</foreach>
|
||||
) AS matched_words
|
||||
FROM spam_keywords
|
||||
WHERE
|
||||
<foreach item="word" index="index" collection="words" separator=" OR ">
|
||||
FIND_IN_SET(#{word}, REPLACE(chc_keywords, ', ', ',')) > 0
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<update id="updateByKeywordsAndChcKeywordsWhereSpamId" parameterType="spamVO">
|
||||
|
||||
UPDATE spam_keywords
|
||||
SET keywords = #{keywords},
|
||||
chc_keywords = #{chcKeywords}
|
||||
WHERE spam_id = #{spamId}
|
||||
|
||||
</update>
|
||||
|
||||
|
||||
|
||||
|
||||
</mapper>
|
||||
@ -216,14 +216,16 @@ function oneStopReporingTimer() {
|
||||
}
|
||||
|
||||
|
||||
function fn_oneReportCntAndTime(){
|
||||
function fn_oneReportCntAndTime(userId){
|
||||
|
||||
// 폼 데이터를 수집
|
||||
var formData = new FormData($("#divOneSms .sendForm")[0]);
|
||||
|
||||
var jsonObject = {};
|
||||
formData.forEach((value, key) => {
|
||||
jsonObject[key] = value;
|
||||
if (!(value instanceof File)) {
|
||||
jsonObject[key] = value;
|
||||
}
|
||||
});
|
||||
jsonObject['userId'] = userId;
|
||||
|
||||
@ -239,9 +241,15 @@ function fn_oneReportCntAndTime(){
|
||||
|
||||
if (data.status == 'OK') {
|
||||
var cnt = data.data;
|
||||
$('#divOneSmsCard .reportStartCnt').text(cnt);
|
||||
|
||||
$('#divOneSmsCard .reportSndCnt').text(cnt);
|
||||
if(cnt == 0){
|
||||
var transferCnt = $('#divOneSmsCard .insertCnt').text();
|
||||
|
||||
|
||||
console.log('cnt : ', cnt);
|
||||
console.log('reportStartCnt : ', transferCnt);
|
||||
console.log('');
|
||||
if(cnt >= Number(transferCnt)){
|
||||
oneStopReporingTimer();
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,8 +245,9 @@ function fn_twoReportCntAndTime(userId){
|
||||
if (data.status == 'OK') {
|
||||
var cnt = data.data;
|
||||
|
||||
console.log('cnt : ', cnt);
|
||||
// 리포트 영역에 cnt 추가
|
||||
$('#divTwoSmsCard .reportSndCnt').text(cnt);
|
||||
$('#divTwoSmsCard .reportStartCnt').text(cnt);
|
||||
// server DB에 update한 건수와 cnt비교
|
||||
var transferCnt = $('#divTwoSmsCard .insertCnt').text();
|
||||
|
||||
|
||||
@ -117,7 +117,7 @@
|
||||
title: title,
|
||||
subtitle: '',
|
||||
autohide : true,
|
||||
delay: 3000,
|
||||
delay: 6000,
|
||||
body: msg
|
||||
})
|
||||
}
|
||||
|
||||
@ -113,6 +113,14 @@
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav nav-treeview">
|
||||
<li class="nav-item">
|
||||
<a th:href="@{/mjon/spam/chk}" class="nav-link">
|
||||
<i class="fas fa-filter nav-icon"></i>
|
||||
<p>스팸비교</p>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
@ -150,7 +150,7 @@
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">닫기</button>
|
||||
<button type="button" class="btn btn-primary" onclick="updateCodeGroup()">저장</button>
|
||||
<button type="button" class="btn btn-primary" onclick="updateCodeGroup()">수정</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -239,6 +239,56 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 공통 코드 상세 수정 모달 -->
|
||||
<div class="modal fade" id="editCodeDetailModal" tabindex="-1" role="dialog" aria-labelledby="editCodeDetailModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="editCodeDetailModalLabel">공통 코드 상세 수정</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="editCodeDetailForm">
|
||||
<div class="form-group">
|
||||
<label for="editDetailCodeId">코드 ID</label>
|
||||
<input type="text" class="form-control" id="editDetailCodeId" name="codeId" readonly>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="editDetailCodeGroupId">코드 그룹 ID</label>
|
||||
<input type="text" class="form-control" id="editDetailCodeGroupId" name="codeGroupId" readonly>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="editDetailCodeName">코드 이름</label>
|
||||
<input type="text" class="form-control" id="editDetailCodeName" name="codeName" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="editDetailCodeValue">코드 값</label>
|
||||
<input type="text" class="form-control" id="editDetailCodeValue" name="codeValue" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="editDetailSortOrder">정렬 순서</label>
|
||||
<input type="number" class="form-control" id="editDetailSortOrder" name="sortOrder">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="editDetailUseYn">사용 여부</label>
|
||||
<select class="form-control" id="editDetailUseYn" name="useYn">
|
||||
<option value="Y">Yes</option>
|
||||
<option value="N">No</option>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">닫기</button>
|
||||
<button type="button" class="btn btn-primary" onclick="updateCodeDetail()">수정</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<footer class="main-footer" th:insert="~{fragments/footer :: footerFragment}"></footer>
|
||||
|
||||
<!-- Control Sidebar -->
|
||||
@ -373,8 +423,8 @@
|
||||
'<td>' + detail.codeValue + '</td>' +
|
||||
'<td>' + detail.sortOrder + '</td>' +
|
||||
'<td>' + detail.useYn + '</td>' +
|
||||
'<td><button class="btn btn-primary btn-sm" onclick="editCodeDetail(\'' + detail.codeId + '\')">수정</button></td>' +
|
||||
'<td><button class="btn btn-danger btn-sm" onclick="deleteCodeDetail(\'' + detail.codeId + '\')">삭제</button></td>' +
|
||||
'<td><button class="btn btn-primary btn-sm" onclick="editCodeDetail(\'' + codeGroupId + '\', \'' + detail.codeId + '\')">수정</button></td>' +
|
||||
'<td><button class="btn btn-danger btn-sm" onclick="deleteCodeDetail(\'' + codeGroupId+'\', \'' + detail.codeId + '\')">삭제</button></td>' +
|
||||
'</tr>');
|
||||
});
|
||||
$('#commonCodeDetailModal').modal('show');
|
||||
@ -425,9 +475,17 @@
|
||||
contentType: 'application/json; charset=utf-8',
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
$('#addCodeDetailModal').modal('hide'); // 모달 닫기
|
||||
showDetails(formData.codeGroupId); // 상세 보기 갱신
|
||||
fn_successAlert("성공", data.data +'가 '+data.msg);
|
||||
|
||||
if(data.status === 'OK'){
|
||||
|
||||
$('#addCodeDetailForm')[0].reset(); // form reset
|
||||
$('#addCodeDetailModal').modal('hide'); // 모달 닫기
|
||||
showDetails(formData.codeGroupId); // 상세 보기 갱신
|
||||
fn_successAlert("성공", data.data +'가 '+data.msg);
|
||||
}else{
|
||||
fn_failedAlert("실패", data.msg);
|
||||
}
|
||||
|
||||
},
|
||||
error: function(xhr) {
|
||||
alert('공통 코드 상세 추가 중 오류가 발생했습니다.');
|
||||
@ -435,29 +493,64 @@
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 코드 상세 추가 함수
|
||||
window.addCodeDetail = function() {
|
||||
// 코드 상세 추가 모달을 띄우거나, 필요한 로직 추가
|
||||
// 코드 상세 수정 모달을 표시하는 함수
|
||||
window.editCodeDetail = function(codeGroupId, codeId) {
|
||||
$.ajax({
|
||||
url: '/api/code-details/detail/' + codeGroupId + '/' + codeId, // API 엔드포인트
|
||||
type: 'GET',
|
||||
success: function(data) {
|
||||
$('#editDetailCodeId').val(data.codeId);
|
||||
$('#editDetailCodeGroupId').val(data.codeGroupId);
|
||||
$('#editDetailCodeName').val(data.codeName);
|
||||
$('#editDetailCodeValue').val(data.codeValue);
|
||||
$('#editDetailSortOrder').val(data.sortOrder);
|
||||
$('#editDetailUseYn').val(data.useYn);
|
||||
$('#editCodeDetailModal').modal('show'); // 수정 모달 표시
|
||||
},
|
||||
error: function(xhr) {
|
||||
alert('코드 상세 정보를 불러오는 데 실패했습니다.');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 코드 상세 수정 함수
|
||||
window.editCodeDetail = function(codeId) {
|
||||
// 코드 상세 수정 로직 추가
|
||||
window.updateCodeDetail = function() {
|
||||
var formDataArray = $("#editCodeDetailForm").serializeArray();
|
||||
var formData = {};
|
||||
|
||||
// 배열 데이터를 JSON 객체로 변환
|
||||
$.each(formDataArray, function(_, field) {
|
||||
formData[field.name] = field.value;
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
url: '/api/code-details/detail/' + formData.codeId, // API 엔드포인트
|
||||
type: 'PUT',
|
||||
data: JSON.stringify(formData),
|
||||
dataType: 'json',
|
||||
contentType: 'application/json; charset=utf-8',
|
||||
success: function(data) {
|
||||
$('#editCodeDetailModal').modal('hide'); // 모달 닫기
|
||||
showDetails(formData.codeGroupId); // 상세 보기 갱신
|
||||
fn_successAlert("성공", data.data +'가 '+data.msg);
|
||||
},
|
||||
error: function(xhr) {
|
||||
alert('코드 상세 수정 중 오류가 발생했습니다.');
|
||||
console.log('xhr : ', xhr);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 코드 상세 삭제 함수
|
||||
window.deleteCodeDetail = function(codeId) {
|
||||
window.deleteCodeDetail = function(codeGroupId, codeId) {
|
||||
|
||||
if(confirm('삭제하시겠습니까?')) {
|
||||
$.ajax({
|
||||
url: '/api/code-details/detail/' + codeId, // 변경된 URL
|
||||
url: '/api/code-details/detail/' + codeGroupId + '/' + codeId, // 변경된 URL
|
||||
type: 'DELETE',
|
||||
success: function(response) {
|
||||
showDetails($('#detailTableBody').data('group-id')); // 갱신을 위해 다시 로드
|
||||
showDetails(codeGroupId); // 갱신을 위해 다시 로드
|
||||
},
|
||||
error: function(xhr) {
|
||||
alert('오류가 발생했습니다.');
|
||||
|
||||
199
src/main/resources/templates/mjon/spam/chk.html
Normal file
199
src/main/resources/templates/mjon/spam/chk.html
Normal file
@ -0,0 +1,199 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en"
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
layout:decorate="layout">
|
||||
<head>
|
||||
<title>스팸 단어 선택</title>
|
||||
|
||||
<link rel="stylesheet" th:href="@{/plugins/datatables-bs4/css/dataTables.bootstrap4.min.css}">
|
||||
<link rel="stylesheet" th:href="@{/plugins/datatables-responsive/css/responsive.bootstrap4.min.css}">
|
||||
<link rel="stylesheet" th:href="@{/plugins/datatables-buttons/css/buttons.bootstrap4.min.css}">
|
||||
|
||||
<style>
|
||||
.table-fixed thead {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1020;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.table-fixed tbody td, .table-fixed thead th {
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* 중앙 정렬을 위한 추가 스타일 */
|
||||
.center-align {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
/* 통계 정보 구분 */
|
||||
.stats-info {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
/* 메시지 입력과 버튼 정렬을 위한 스타일 */
|
||||
.input-group {
|
||||
display: flex;
|
||||
align-items: stretch; /* 세로 높이 맞추기 */
|
||||
}
|
||||
|
||||
.input-group textarea {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.input-group button {
|
||||
align-self: stretch; /* 버튼 높이를 textarea에 맞춤 */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body layout:fragment="body">
|
||||
|
||||
<div class="wrapper">
|
||||
<div th:replace="~{fragments/top_nav :: topFragment}"></div>
|
||||
|
||||
<!-- Main Sidebar Container -->
|
||||
<aside class="main-sidebar sidebar-dark-primary elevation-4"
|
||||
th:insert="~{fragments/mainsidebar :: sidebarFragment}">
|
||||
</aside>
|
||||
|
||||
<!-- Content Wrapper. Contains page content -->
|
||||
<div class="content-wrapper">
|
||||
<!-- Content Header (Page header) -->
|
||||
<div class="content-header">
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6">
|
||||
<h1 class="m-0">스팸 비교</h1>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<ol class="breadcrumb float-sm-right">
|
||||
<li class="breadcrumb-item"><a href="#">Home</a></li>
|
||||
<li class="breadcrumb-item active">스팸 비교</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.content-header -->
|
||||
|
||||
<!-- Main content -->
|
||||
<section class="content">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">스팸 비교</h3>
|
||||
</div>
|
||||
<!-- /.card-header -->
|
||||
|
||||
<div class="card-body p-0">
|
||||
<div class="container-fluid">
|
||||
<!-- 메시지 입력과 버튼 영역 -->
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="input-group">
|
||||
<textarea class="form-control" id="inputMessage" rows="3" placeholder="메시지를 입력하세요" style="width: 90%;"></textarea>
|
||||
<button type="button" class="btn btn-primary" style="width: 10%;">조회</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 불법/성인 버튼 중앙 정렬 -->
|
||||
<div class="row">
|
||||
<div class="col-12 d-flex justify-content-center flex-wrap">
|
||||
<button type="button" class="btn btn-primary mx-2 my-2">불법 145건</button>
|
||||
<button type="button" class="btn btn-secondary mx-2 my-2">성인 43건</button>
|
||||
<button type="button" class="btn btn-success mx-2 my-2">광고 78건</button>
|
||||
<button type="button" class="btn btn-danger mx-2 my-2">금융 20건</button>
|
||||
<button type="button" class="btn btn-warning mx-2 my-2">스팸 30건</button>
|
||||
<button type="button" class="btn btn-info mx-2 my-2">게임 15건</button>
|
||||
<button type="button" class="btn btn-light mx-2 my-2">의료 9건</button>
|
||||
<button type="button" class="btn btn-dark mx-2 my-2">기타 12건</button>
|
||||
<button type="button" class="btn btn-outline-primary mx-2 my-2">교육 5건</button>
|
||||
<button type="button" class="btn btn-outline-secondary mx-2 my-2">이벤트 22건</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 통계 정보 영역 -->
|
||||
<div class="row stats-info">
|
||||
<div class="col-12">
|
||||
<span>문자 개수 총 300건</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 스팸 비교 테이블 영역 -->
|
||||
<div class="row mt-3">
|
||||
<div class="col-12">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>번호</th>
|
||||
<th>스팸문자</th>
|
||||
<th>핵심단어</th>
|
||||
<th>매칭단어 개수</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>(광고)♥봄맞이 특별이벤트 진행중♥ ...</td>
|
||||
<td>바다, 서비스, 갯수...</td>
|
||||
<td>3</td>
|
||||
</tr>
|
||||
<!-- 추가 행들 필요 시 여기 추가 -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.card-body -->
|
||||
</div>
|
||||
<!-- /.card -->
|
||||
</div>
|
||||
<!-- /.col -->
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
</div>
|
||||
<!-- /.container-fluid -->
|
||||
</section>
|
||||
<!-- /Main content -->
|
||||
</div>
|
||||
<!-- /.content-wrapper -->
|
||||
|
||||
<footer class="main-footer"
|
||||
th:insert="~{fragments/footer :: footerFragment}">
|
||||
</footer>
|
||||
|
||||
<!-- Control Sidebar -->
|
||||
<aside class="control-sidebar control-sidebar-dark">
|
||||
<!-- Control sidebar content goes here -->
|
||||
</aside>
|
||||
<!-- /.control-sidebar -->
|
||||
</div>
|
||||
<!-- ./wrapper -->
|
||||
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
// 조회 버튼 클릭 시 이벤트 핸들러
|
||||
$('button.btn-primary').on('click', function () {
|
||||
var inputMessage = $('#inputMessage').val();
|
||||
// AJAX 호출이나 데이터 처리 로직 추가 가능
|
||||
alert('조회 버튼 클릭! 입력된 메시지: ' + inputMessage);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -111,28 +111,30 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 5%;">번호</th>
|
||||
<th style="width: 25%;">스팸문자</th>
|
||||
<th style="width: 35%;">복합명사</th>
|
||||
<th style="width: 25%;">핵심 단어</th>
|
||||
<th style="width: 10%;">스팸분류</th>
|
||||
<th style="width: 20%;">스팸문자</th>
|
||||
<th style="width: 25%;">복합명사</th>
|
||||
<th style="width: 20%;">핵심 단어</th>
|
||||
<th style="width: 10%;">스팸분류01</th>
|
||||
<th style="width: 10%;">스팸분류02</th>
|
||||
<!-- <th style="width: 10%;">확정</th>-->
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="spam, iterStat : ${spamList}">
|
||||
<td th:text="${iterStat.index + 1}"></td>
|
||||
<td th:text="${(pagingVO.pageNum - 1) * pagingVO.pageSize + iterStat.index + 1}"></td>
|
||||
<td th:text="${spam.smsTxt}">스팸문자 내용</td>
|
||||
<td>
|
||||
<span th:each="word : ${spam.keywordList}">
|
||||
<!--
|
||||
- adminLTE3 css 참고
|
||||
btn: 버튼 스타일을 적용합니다.
|
||||
btn-primary: 파란색 배경의 버튼을 만듭니다. 다른 색상은 btn-secondary, btn-success, btn-danger 등으로 변경할 수 있습니다.
|
||||
btn-sm: 작은 크기의 버튼을 만듭니다.
|
||||
rounded-pill: 모서리를 둥글게 처리하여 pill 형태의 버튼을 만듭니다.
|
||||
<!--
|
||||
- adminLTE3 css 참고
|
||||
btn: 버튼 스타일을 적용합니다.
|
||||
btn-primary: 파란색 배경의 버튼을 만듭니다. 다른 색상은 btn-secondary, btn-success, btn-danger 등으로 변경할 수 있습니다.
|
||||
btn-sm: 작은 크기의 버튼을 만듭니다.
|
||||
rounded-pill: 모서리를 둥글게 처리하여 pill 형태의 버튼을 만듭니다.
|
||||
|
||||
mx-1: 좌우에 0.25rem(약 4px)의 여백 추가
|
||||
my-1: 상하에 0.25rem(약 4px)의 여백 추가
|
||||
-->
|
||||
mx-1: 좌우에 0.25rem(약 4px)의 여백 추가
|
||||
my-1: 상하에 0.25rem(약 4px)의 여백 추가
|
||||
-->
|
||||
<span th:each="word : ${spam.keywordList}">
|
||||
<button class="btn btn-primary rounded-pill mx-1 my-1"
|
||||
th:text="${word}"
|
||||
th:data-spamid="${spam.spamId}"
|
||||
@ -141,15 +143,43 @@
|
||||
</span>
|
||||
</td>
|
||||
<!-- <td th:text="${spam.keywords}">복합명사 목록</td>-->
|
||||
<td th:text="${spam.chcKeywords}">핵심 단어 목록</td>
|
||||
<td>
|
||||
<select class="form-control" th:value="${spam.categ}">
|
||||
<option>선택</option>
|
||||
<option value="성인">성인</option>
|
||||
<option value="불법">불법</option>
|
||||
<option value="해당없음">해당없음</option>
|
||||
<span th:each="word : ${spam.chcKeywordList}">
|
||||
<button class="btn btn-success rounded-pill mx-1 my-1"
|
||||
th:text="${word}"
|
||||
th:data-spamid="${spam.spamId}"
|
||||
th:data-word="${word}"
|
||||
th:data-original-td="2"
|
||||
th:data-current-td="3"
|
||||
onclick="handleClick(this)"></button>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<select class="form-control select2 rsnCode01"
|
||||
onchange="updateCode02Options(this)">
|
||||
<option value="">선택해주세요.</option>
|
||||
<option th:each="code : ${rsnCode01List}"
|
||||
th:value="${code.codeId}"
|
||||
th:text="${code.codeName}"
|
||||
th:selected="${code.codeId} == ${spam.spamRsnCode01}">
|
||||
Code
|
||||
</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<select class="form-control select2 rsnCode02">
|
||||
<option value="">선택해주세요.</option>
|
||||
<option th:each="code : ${spam.codeDetailList}"
|
||||
th:value="${code.codeId}"
|
||||
th:text="${code.codeName}"
|
||||
th:selected="${code.codeId} == ${spam.spamRsnCode02}">
|
||||
Code
|
||||
</option>
|
||||
</select>
|
||||
</td>
|
||||
<!-- <td>-->
|
||||
<!-- <button class="btn btn-success btn-confirm" data-spamid="${spam.spamId}" onclick="confirmSpam(this)">확정</button>-->
|
||||
<!-- </td>-->
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@ -209,34 +239,137 @@
|
||||
</div>
|
||||
<!-- ./wrapper -->
|
||||
|
||||
<!-- <!– DataTables & Plugins –>-->
|
||||
<!-- <script th:src="@{/plugins/datatables/jquery.dataTables.min.js}"></script>-->
|
||||
<!-- <script th:src="@{/plugins/datatables-bs4/js/dataTables.bootstrap4.min.js}"></script>-->
|
||||
<!-- <script th:src="@{/plugins/datatables-responsive/js/dataTables.responsive.min.js}"></script>-->
|
||||
<!-- <script th:src="@{/plugins/datatables-responsive/js/responsive.bootstrap4.min.js}"></script>-->
|
||||
<!-- <script th:src="@{/plugins/datatables-buttons/js/dataTables.buttons.min.js}"></script>-->
|
||||
<!-- <script th:src="@{/plugins/datatables-buttons/js/buttons.bootstrap4.min.js}"></script>-->
|
||||
<!-- <script th:src="@{/plugins/jszip/jszip.min.js}"></script>-->
|
||||
<!-- <script th:src="@{/plugins/pdfmake/pdfmake.min.js}"></script>-->
|
||||
<!-- <script th:src="@{/plugins/pdfmake/vfs_fonts.js}"></script>-->
|
||||
<!-- <script th:src="@{/plugins/datatables-buttons/js/buttons.html5.min.js}"></script>-->
|
||||
<!-- <script th:src="@{/plugins/datatables-buttons/js/buttons.print.min.js}"></script>-->
|
||||
<!-- <script th:src="@{/plugins/datatables-buttons/js/buttons.colVis.min.js}"></script>-->
|
||||
<script>
|
||||
$(function () {
|
||||
$(document).ready(function() {
|
||||
// 초기화 이후에 값을 출력
|
||||
// $('.rsnCode01').each(function() {
|
||||
// console.log($(this).val());
|
||||
// });
|
||||
|
||||
});
|
||||
|
||||
|
||||
function handleClick(button) {
|
||||
var spamId = button.getAttribute('data-spamid');
|
||||
var word = button.getAttribute('data-word');
|
||||
console.log("Spam ID:", spamId, "Word:", word);
|
||||
// 여기에 추가적인 로직을 구현하세요.
|
||||
var currentTd = button.parentElement.parentElement; // 현재 td 요소
|
||||
var nextTd;
|
||||
|
||||
// 부모 요소인 span을 찾아서 제거
|
||||
var span = button.parentElement;
|
||||
span.remove();
|
||||
// 버튼이 처음 클릭된 상태인지 확인하기 위해 data-original-td 속성을 체크
|
||||
if (!button.hasAttribute('data-original-td')) {
|
||||
// 초기 클릭 시, 원래의 td를 data-original-td 속성에 저장
|
||||
button.setAttribute('data-original-td', currentTd.cellIndex);
|
||||
button.setAttribute('data-current-td', currentTd.cellIndex);
|
||||
}
|
||||
|
||||
var originalTdIndex = button.getAttribute('data-original-td'); // 원래 td의 인덱스
|
||||
var currentTdIndex = button.getAttribute('data-current-td'); // 현재 td의 인덱스
|
||||
|
||||
if (currentTdIndex == originalTdIndex) {
|
||||
// 버튼이 원래 위치에 있는 경우 다음 td로 이동
|
||||
nextTd = currentTd.nextElementSibling;
|
||||
button.setAttribute('data-current-td', nextTd.cellIndex);
|
||||
} else {
|
||||
// 버튼이 다음 위치에 있는 경우 원래 위치로 이동
|
||||
nextTd = currentTd.previousElementSibling;
|
||||
button.setAttribute('data-current-td', originalTdIndex);
|
||||
}
|
||||
|
||||
if (nextTd) {
|
||||
// 버튼을 새 span으로 감싸서 다음 또는 이전 td에 추가
|
||||
var newSpan = document.createElement('span');
|
||||
newSpan.appendChild(button);
|
||||
|
||||
// 버튼의 CSS 클래스 변경 (색상 변경)
|
||||
if (currentTdIndex == originalTdIndex) {
|
||||
button.classList.remove('btn-primary'); // 기존 색상 클래스 제거
|
||||
button.classList.add('btn-success'); // 새 색상 클래스 추가
|
||||
fn_chcKeywordUpdate(spamId, word);
|
||||
} else {
|
||||
button.classList.remove('btn-success'); // 기존 색상 클래스 제거
|
||||
button.classList.add('btn-primary'); // 원래 색상 클래스 추가
|
||||
fn_keywordUpdate(spamId, word);
|
||||
}
|
||||
|
||||
// 다음 또는 이전 td에 새로운 span 추가
|
||||
nextTd.appendChild(newSpan);
|
||||
}
|
||||
}
|
||||
|
||||
//rsnCode01 onchange
|
||||
function updateCode02Options(selectElement) {
|
||||
var codeGroup = $(selectElement).val(); // 선택된 spam_rsn_code_01 값 가져오기
|
||||
|
||||
// selectElement의 부모 <td>의 다음 <td>를 찾고, 그 안의 .rsnCode02 클래스를 가진 <select> 요소를 선택
|
||||
var code02Select = $(selectElement).closest('td').next('td').find('.rsnCode02');
|
||||
|
||||
if (codeGroup) {
|
||||
// 서버에 AJAX 요청 보내기
|
||||
$.ajax({
|
||||
url: '/api/code-details/' + "SPAM"+codeGroup,
|
||||
method: 'GET',
|
||||
success: function(data) {
|
||||
// 현재의 옵션들을 제거하고 새로운 옵션으로 대체
|
||||
code02Select.empty();
|
||||
code02Select.append('<option value="">선택해주세요.</option>');
|
||||
data.forEach(function(code) {
|
||||
code02Select.append('<option value="' + code.codeId + '">' + code.codeName + '</option>');
|
||||
});
|
||||
|
||||
// spam.spamRsnCode02에 대한 초기 선택 설정 (만약 필요한 경우)
|
||||
var selectedCode02 = code02Select.data('selected-value');
|
||||
if (selectedCode02) {
|
||||
code02Select.val(selectedCode02);
|
||||
}
|
||||
},
|
||||
error: function(xhr) {
|
||||
console.error("Failed to fetch code details.");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
code02Select.empty();
|
||||
code02Select.append('<option value="">선택해주세요.</option>');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function fn_keywordUpdate(spamId, word){
|
||||
|
||||
// 한글이 포함된 word를 URL 인코딩합니다.
|
||||
var encodedWord = encodeURIComponent(word);
|
||||
$.ajax({
|
||||
url: '/mjon/spam/keyword/' + spamId + '/' + encodedWord,
|
||||
type: 'PUT',
|
||||
success: function(data) {
|
||||
fn_successAlert("성공", data.msg);
|
||||
},
|
||||
error: function(xhr, data) {
|
||||
|
||||
fn_failedAlert("실패", data.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fn_chcKeywordUpdate(spamId, word){
|
||||
|
||||
// 한글이 포함된 word를 URL 인코딩합니다.
|
||||
var encodedWord = encodeURIComponent(word);
|
||||
$.ajax({
|
||||
url: '/mjon/spam/chcKeyword/' + spamId + '/' + encodedWord,
|
||||
type: 'PUT',
|
||||
success: function(data) {
|
||||
fn_successAlert("성공", data.msg);
|
||||
},
|
||||
error: function(xhr, data) {
|
||||
|
||||
fn_failedAlert("실패", data.msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
// fn_failedAlert("실패", data.msg);
|
||||
// fn_successAlert("성공", data.data +'가 '+data.msg);
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user