kccf/.claude/skills/egov-crud-module/references/patterns.md
ythong 80b5ed1da4 Initial commit - KCCF 문화원연합회 누리집
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 11:38:15 +09:00

256 lines
8.4 KiB
Markdown

# eGovFramework KCCF 코드 패턴 레퍼런스
## VO 완성 패턴
```java
package kccf.{module}.vo;
import kccf.cmm.vo.CmmBaseVO;
import lombok.*;
@Setter @Getter @ToString
@NoArgsConstructor @AllArgsConstructor
public class {Module}VO extends CmmBaseVO {
/* {한글명} 아이디 */
private String {module}Id;
/* {한글명}명 */
private String {module}Nm;
/* 지역코드 */
private String areaCode;
/* 삭제여부 */
private String deleteAt;
/* 등록자 아이디 */
private String regUserId;
/* 등록자명 */
private String regUserNm;
/* 등록일시 */
private String regDttm;
/* 수정자 아이디 */
private String updUserId;
/* 수정일시 */
private String updDttm;
/* 검색 - {조건명} */
private String search{Field};
/* 권한 관련 */
private boolean canReadOther;
private boolean canWrite;
private boolean canUpdate;
}
```
## DAO 패턴
```java
package kccf.{module}.dao;
import java.util.List;
import kccf.cmm.dao.CmmBaseDAO;
import kccf.{module}.vo.{Module}VO;
import org.springframework.stereotype.Repository;
@Repository
public class {Module}DAO extends CmmBaseDAO {
public List<{Module}VO> select{Module}List({Module}VO vo) {
return selectList("kccf.{module}.dao.{Module}DAO.select{Module}List", vo);
}
public {Module}VO select{Module}Detail({Module}VO vo) {
return selectOne("kccf.{module}.dao.{Module}DAO.select{Module}Detail", vo);
}
public void insert{Module}({Module}VO vo) {
insert("kccf.{module}.dao.{Module}DAO.insert{Module}", vo);
}
public void update{Module}({Module}VO vo) {
update("kccf.{module}.dao.{Module}DAO.update{Module}", vo);
}
public void delete{Module}({Module}VO vo) {
delete("kccf.{module}.dao.{Module}DAO.delete{Module}", vo);
}
public String get{Module}IdSeq() {
return selectOne("kccf.{module}.dao.{Module}DAO.get{Module}IdSeq", null);
}
}
```
## Service / ServiceImpl 패턴
```java
// Service 인터페이스
public interface {Module}Service {
List<{Module}VO> select{Module}List({Module}VO vo);
{Module}VO select{Module}Detail({Module}VO vo);
void insert{Module}({Module}VO vo);
void update{Module}({Module}VO vo);
void delete{Module}({Module}VO vo);
String get{Module}IdSeq();
}
// ServiceImpl
@Service
@RequiredArgsConstructor
public class {Module}ServiceImpl implements {Module}Service {
private final {Module}DAO {module}DAO;
@Override public List<{Module}VO> select{Module}List({Module}VO vo) { return {module}DAO.select{Module}List(vo); }
// ... 나머지 메서드
}
```
## Controller 완성 패턴
```java
@Controller
@RequiredArgsConstructor
@RequestMapping(value = "/sec/{module}")
public class {Module}Controller extends CmmBaseController {
private final {Module}Service {module}Service;
private final KccfLoginService kccfLoginService;
@RequestMapping(value = "/{module}ListPage.do")
public String {module}ListPage({Module}VO searchVO, ModelMap model, HttpSession session) {
UserVO userVO = (UserVO)session.getAttribute("user");
if(userVO == null || StringUtils.isAllBlank(userVO.getUserId())) {
return "redirect:/login.do";
}
// 코드 목록 로딩
CmmnCodeDetailVO cmmVO = new CmmnCodeDetailVO();
cmmVO.setCode("AREA_CODE");
model.addAttribute("areaCodeList", kccfLoginService.selectCodeListAjax(cmmVO));
searchVO.setCanWrite(AuthUtil.canWrite(getUserId(), getSiteSeCode(), getSelMenuId(), ""));
model.addAttribute("searchVO", searchVO);
return model.getAttribute("hostId") + "/{module}/list{Module}";
}
@RequestMapping(value = "/select{Module}ListAjax.do")
public String select{Module}ListAjax({Module}VO searchVO, ModelMap model) {
List<{Module}VO> list = {module}Service.select{Module}List(searchVO);
if(list != null && list.size() > 0) {
searchVO.setTotCnt(list.get(0).getTotCnt());
}
model.addAttribute("data", list);
model.addAttribute("searchVO", searchVO);
return "jsonView";
}
@RequestMapping(value = "/{module}DetailPage.do")
public String {module}DetailPage({Module}VO searchVO, ModelMap model, HttpSession session) {
UserVO userVO = (UserVO)session.getAttribute("user");
if(userVO == null || StringUtils.isAllBlank(userVO.getUserId())) {
return "redirect:/login.do";
}
if(searchVO.get{Module}Id() != null && !searchVO.get{Module}Id().isEmpty()) {
model.addAttribute("{module}VO", {module}Service.select{Module}Detail(searchVO));
}
searchVO.setCanWrite(AuthUtil.canWrite(getUserId(), getSiteSeCode(), getSelMenuId(), ""));
model.addAttribute("searchVO", searchVO);
return model.getAttribute("hostId") + "/{module}/{module}Regist";
}
@RequestMapping(value = "/insert{Module}.do")
public String insert{Module}({Module}VO searchVO, RedirectAttributes redirect) {
searchVO.setRegUserId(getUserId());
searchVO.setUpdUserId(getUserId());
if(searchVO.get{Module}Id() != null && !searchVO.get{Module}Id().isEmpty()) {
{module}Service.update{Module}(searchVO);
} else {
searchVO.set{Module}Id({module}Service.get{Module}IdSeq());
{module}Service.insert{Module}(searchVO);
}
redirect.addAttribute("pageNo", searchVO.getPageNo());
redirect.addAttribute("selMenuId", searchVO.getSelMenuId());
return "redirect:/sec/{module}/{module}ListPage.do";
}
@RequestMapping(value = "/delete{Module}.do")
public String delete{Module}({Module}VO searchVO, RedirectAttributes redirect) {
{module}Service.delete{Module}(searchVO);
redirect.addAttribute("pageNo", searchVO.getPageNo());
redirect.addAttribute("selMenuId", searchVO.getSelMenuId());
return "redirect:/sec/{module}/{module}ListPage.do";
}
}
```
## MyBatis Mapper XML 패턴
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kccf.{module}.dao.{Module}DAO">
<select id="select{Module}List" parameterType="{Module}VO" resultType="{Module}VO">
SELECT A.*
, ROW_NUMBER() OVER (ORDER BY A.REG_DTTM DESC) AS rn
, COUNT(*) OVER () AS totCnt
FROM TB_{MODULE} A
WHERE A.DELETE_AT = 'N'
<where>
<if test="searchAreaCode != null and searchAreaCode != ''">
AND A.AREA_CODE = #{searchAreaCode}
</if>
<if test="search{Module}Nm != null and search{Module}Nm != ''">
AND A.{MODULE}_NM LIKE '%' || #{search{Module}Nm} || '%'
</if>
</where>
ORDER BY A.REG_DTTM DESC
</select>
<select id="select{Module}Detail" parameterType="{Module}VO" resultType="{Module}VO">
SELECT A.*
FROM TB_{MODULE} A
WHERE A.{MODULE}_ID = #{module}Id}
</select>
<insert id="insert{Module}" parameterType="{Module}VO">
INSERT INTO TB_{MODULE} (
{MODULE}_ID, {MODULE}_NM, AREA_CODE,
DELETE_AT, REG_USER_ID, REG_DTTM, UPD_USER_ID, UPD_DTTM
) VALUES (
#{module}Id}, #{module}Nm}, #{areaCode},
'N', #{regUserId}, SYSDATE, #{updUserId}, SYSDATE
)
</insert>
<update id="update{Module}" parameterType="{Module}VO">
UPDATE TB_{MODULE}
SET {MODULE}_NM = #{module}Nm}
, AREA_CODE = #{areaCode}
, UPD_USER_ID = #{updUserId}
, UPD_DTTM = SYSDATE
WHERE {MODULE}_ID = #{module}Id}
</update>
<update id="delete{Module}" parameterType="{Module}VO">
UPDATE TB_{MODULE}
SET DELETE_AT = 'Y'
, UPD_USER_ID = #{updUserId}
, UPD_DTTM = SYSDATE
WHERE {MODULE}_ID = #{module}Id}
</update>
<select id="get{Module}IdSeq" resultType="String">
SELECT LPAD(NVL(MAX(TO_NUMBER({MODULE}_ID)), 0) + 1, 10, '0')
FROM TB_{MODULE}
</select>
</mapper>
```
## 주의사항
- `SYSDATE`: Oracle/Altibase 전용 → MySQL/MariaDB에서는 `NOW()`
- `ROW_NUMBER() OVER (...)`: Oracle/Altibase/PostgreSQL 지원 → MySQL 5.7 이하 미지원 (서브쿼리 대체)
- `||` 문자열 연결: Oracle/PostgreSQL → MySQL은 `CONCAT()`
- 현재 DB 설정은 `egov-com-datasource.xml` 또는 application 설정에서 확인