05. 📁 Код бүтэц болон загвар
5.1 MVC загвар хэрэгжүүлэлт
HONGIKINGAN CMS нь Spring MVC загварт суурилан хэрэгжүүлэгдсэн бөгөөд давхарга бүр тодорхой тусгаарлагдсан байдаг.
5.1.1 Controller бүтэц
Контроллер нь клиентийн хүсэлтийг хүлээн авч, тохирох сервисийг дуудаж, үр дүнг харагдах хэсэгт дамжуулах үүрэгтэй.
Үндсэн онцлог
- Хүсэлтийн параметр шалгах
- Алдаа боловсруулах
- Хариу өгөгдөл форматлах
- HumanAbstractController-ээс удамшуулан хэрэгжүүлэх
- eGovFrame стандарт архитектур дагах
[Кодын байршил] humanframe.backoffice.controller.bbs.AdminBbsController
@Controller
@RequestMapping("/${humanframe.admin.path}/bbs")
public class AdminBbsController extends HumanAbstractController {
@Resource(name="bbsSettingService")
private BbsSettingService bbsSettingService;
@Resource(name="siteService")
private SiteService siteService;
@Autowired
private MngrSession mngrSession;
@SuppressWarnings("unchecked")
@RequestMapping("list")
public String list(HttpServletRequest request, Model model) throws Exception {
HumanListVO listVO = new HumanListVO(request);
if(mngrSession.getAuthorTy().equals("2") || mngrSession.getAuthorTy().equals("3")){//админ
listVO.setParam("siteNos", mngrSession.getSiteNos().length > 0?mngrSession.getSiteNos():new String[]{"0"});
listVO.setParam("crtrId",mngrSession.getMngrId());
if(mngrSession.getAuthorTy().equals("2")) {
listVO.setParam("bbsNos", "");
}else {
if(mngrSession.getSiteMenus() != null) {
listVO.setParam("bbsNos", mngrSession.getBbsNos().length > 0?mngrSession.getBbsNos():new String[]{"0"});
}else {
listVO.setParam("bbsNos", new String[] {"0"});
}
}
}
listVO = bbsSettingService.boardListVo(listVO);
List<BbsCtgryVO> bbsCtgryList = bbsSettingService.listCtgry(0, null, "BBS");
Map<String, String> paramMap = new HashMap<String, String>();
paramMap.put("useAt", "Y");
List<SiteVO> siteList = siteService.selectSiteListAll(paramMap);
model.addAttribute("listVO", listVO);
model.addAttribute("useAt", CodeMap.USE_AT);
model.addAttribute("bbsTyCode", CommCodeMap.BBS_TY);
model.addAttribute("siteList", siteList);
model.addAttribute("bbsCtgryList", bbsCtgryList);
return "/admin/bbs/list";
}
// бусад методууд...
}
5.1.2 Service давхарга
Сервис давхарга нь бизнес логикийг боловсруулж, гүйлгээг удирдах үүрэгтэй.
Үндсэн онцлог
- Интерфейс суурьтай дизайн
- Гүйлгээ удирдлага
- Бизнес логик хэрэгжүүлэлт
- DAO дуудах болон үр дүн боловсруулах
- EgovAbstractServiceImpl-ээс удамшуулан хэрэгжүүлэх
- eGovFrame стандарт архитектур дагах
[Кодын байршил] humanframe.backoffice.service.BbsSettingService
@SuppressWarnings("rawtypes")
public interface BbsSettingService {
/**
* Самбарын жагсаалтыг харна.
*
* @param listVO Хайлтын нөхцөл
* @return Самбарын жагсаалт
*/
public HumanListVO boardListVo(HumanListVO listVO) throws Exception;
/**
* Самбарын мэдээллийг харна.
*
* @param bbsNo Самбарын дугаар
* @return Самбарын мэдээлэл
*/
public BbsSettingVO retrieveBoardSetting(int bbsNo) throws Exception;
/**
* Самбарын ангиллын жагсаалтыг харна.
*
* @param bbsNo Самбарын дугаар
* @param prefix Угтвар үг
* @param type Төрөл
* @return Ангиллын жагсаалт
*/
public List<BbsCtgryVO> listCtgry(int bbsNo, String prefix, String useTy) throws Exception;
// бусад методууд...
}
[Кодын байршил] humanframe.backoffice.service.impl.BbsSettingServiceImpl
@SuppressWarnings("rawtypes")
@Service("bbsSettingService")
public class BbsSettingServiceImpl extends EgovAbstractServiceImpl implements BbsSettingService {
@Resource(name="bbsSettingDAO")
private BbsSettingDAO bbsSettingDAO;
@Resource(name="bbsScrtyDAO")
private BbsScrtyDAO bbsScrtyDAO;
@Override
public HumanListVO boardListVo(HumanListVO listVO) throws Exception {
return bbsSettingDAO.selectBoardListVO(listVO);
}
@Override
public BbsSettingVO retrieveBoardSetting(int bbsNo) throws Exception {
BbsSettingVO bbsSettingVO = bbsSettingDAO.selectBoardSetting(bbsNo, 0);
if(bbsSettingVO.getCtgryUseAt().equals("Y")) {
List<BbsCtgryVO> ctgryList = bbsSettingDAO.listCtgry(bbsNo, "L", "NTT");
bbsSettingVO.setCtgryList(ctgryList);
}
// ... дунд хэсэг орхигдсон (аюулгүй байдлын тохиргооны логик) ...
return bbsSettingVO;
}
@Override
public List<BbsCtgryVO> listCtgry(int bbsNo, String prefix, String useTy) throws Exception {
return bbsSettingDAO.listCtgry(bbsNo, prefix, useTy);
}
// бусад методууд...
}
5.1.3 DAO болон MyBatis ашиглалт
DAO (Data Access Object) нь өгөгдлийн сантай харилцах үүрэгтэй бөгөөд MyBatis ашиглан SQL асуулгыг удирддаг.
Үндсэн онцлог
- Интерфейс суурьтай маппер
- XML суурьтай SQL удирдлага
- Динамик асуулга дэмжих
- Үр дүнгийн зураглал автоматжуулах
- EgovAbstractMapper-ээс удамшуулсан HumanAbstractMapper-ээс удамшуулан хэрэгжүүлэх
- eGovFrame стандарт архитектур дагах
[Кодын байршил] humanframe.backoffice.dao.BbsSettingDAO
@Repository("bbsSettingDAO")
public class BbsSettingDAO extends HumanAbstractMapper {
public HumanListVO selectBoardListVO(HumanListVO listVO) throws Exception {
return selectListVO(setDomain("boardSetting.selectBoardCount"), setDomain("boardSetting.selectBoardListVO"), listVO);
}
public BbsSettingVO selectBoardSetting(int bbsNo, int siteNo) throws Exception {
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("bbsNo", bbsNo);
if(siteNo > 0){
paramMap.put("siteNo", siteNo);
}
BbsSettingVO bbsSettingVO = (BbsSettingVO)selectOne(setDomain("boardSetting.selectBoardSetting"), paramMap);
return bbsSettingVO;
}
public List<BbsCtgryVO> listCtgry(int bbsNo, String prefix, String useTy) throws Exception {
Map<String, Object> paramMap = new HashMap<String, Object>();
paramMap.put("bbsNo", bbsNo);
paramMap.put("prefix", prefix);
paramMap.put("ctgryUseTy", useTy);
return selectList(setDomain("boardCtgry.listCtgry"), paramMap);
}
// бусад методууд...
}
[Кодын байршил] humanframe/sqlmap/mappers/mysql/human-bbs-ctgry.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="humanframe.boardCtgry">
<resultMap type="bbsCtgryVO" id="bbsCtgryMap">
<result property="bbsNo" column="bbs_no" />
<result property="ctgryNo" column="ctgry_no" />
<result property="ctgryValue" column="ctgry_value" />
<result property="ctgryNm" column="ctgry_nm" />
</resultMap>
<select id="listCtgry" parameterType="hashmap" resultMap="bbsCtgryMap">
SELECT
bbs_no
, ctgry_no
<choose>
<when test="prefix != null">
, CONCAT('${prefix}-' , ctgry_no) AS ctgry_value
</when>
<otherwise>
, '' AS ctgry_value
</otherwise>
</choose>
, ctgry_nm
FROM tn_bbs_ctgry
WHERE bbs_no = #{bbsNo}
AND use_at = 'Y'
</select>
<!-- бусад асуулга... -->
</mapper>
5.2 MVC архитектурын бүтэц
HONGIKINGAN CMS-ийн MVC архитектур нь eGovFrame стандарт фреймворкийн архитектурыг дагаж, дараах онцлогтой:
Controller давхарга
- eGovFrame стандарт архитектур дагах
HumanAbstractController-ээс удамшуулан хэрэгжүүлэх- Controller класс нь DAO классын методыг шууд дуудаж болохгүй
- Service давхаргаар дамжуулан бизнес логик боловсруулах
View давхарга
- JSP, Tiles ашиглан дэлгэц бүрдүүлэх
- JSTL, EL ашиглан өгөгдөл илэрхийлэх
- Хэрэглэгчийн тодорхойлсон таг номын сан ашиглах
Model давхарга
- VO (Value Object) классаар дамжуулан өгөгдөл дамжуулах
- Service давхаргаас бизнес логик боловсруулсны дараа үр дүн буцаах
5.3 Сервисийн архитектурын бүтэц
HONGIKINGAN CMS-ийн сервисийн архитектур нь дараах онцлогтой:
Сервисийн интерфейс
- Бүх сервис интерфейсээр тодорхойлогдоно
- "service" багцад интерфейс байршуулна
Сервисийн хэрэгжүүлэлт
EgovAbstractServiceImpl-ийг өргөтгөж хэрэгжүүлэх- "service/impl" багцад хэрэгжүүлэлт байршуулна
@Serviceаннотацаар дамжуулан bean бүртгэх
Гүйлгээний удирдлага
@Transactionalаннотацаар дамжуулан гүйлгээ удирдах- Зарлалт гүйлгээ удирдлагын арга хэрэглэх
5.4 Өгөгдөлд хандах архитектурын бүтэц
HONGIKINGAN CMS-ийн өгөгдөлд хандах архитектур нь дараах онцлогтой:
DAO класс
- eGovFrame стандарт архитектур дагах
EgovAbstractMapper-ийг өргөтгөсөнHumanAbstractMapper-ээс удамшуулан хэрэгжүүлэх@Repositoryаннотацаар дамжуулан bean бүртгэх
MyBatis маппер
- XML суурьтай SQL удирдлага
- Динамик асуулга дэмжих
- Төрөл бүрийн өгөгдлийн сан дэмжих (CUBRID, Oracle, MySQL, MS-SQL, Tibero)
Өгөгдлийн сан холболт
- JNDI суурьтай өгөгдлийн эх тохиргоо
- Профайл тус бүрийн өгөгдлийн эх тохиргоо (local, dev, prd)
5.5 AOP ашиглалт
HONGIKINGAN CMS нь Aspect Oriented Programming (AOP) ашиглан логлол, эрх шалгах зэрэг нийтлэг сонирхлыг модулчилж байна.
5.5.1 Логлол
Системийн лог болон хэрэглэгчийн үйл ажиллагааны логийг бүртгэхэд AOP ашигладаг.
Үндсэн функц
- Контроллер методын гүйцэтгэл логлох
- Сервис методын гүйцэтгэх хугацаа хэмжих
- Алдаа гарах логлол
- Хэрэглэгчийн үйл ажиллагаа логлох
[Кодын байршил] humanframe.backoffice.aop.aspect.admin.AdminLogAspect
@Aspect
@Order(2)
@Component
public class AdminLogAspect {
@Resource(name = "mngLogService")
private MngLogService mngLogService;
// Админ эрх шалгах
@Pointcut("execution(* humanframe.backoffice..Admin*Controller.form(..))"
+ "|| execution(* humanframe.backoffice..Admin*Controller.list(..))"
+ "|| execution(* humanframe.backoffice..Admin*Controller.view(..))"
+ "|| execution(* humanframe.backoffice..Admin*Controller.action(..))"
+ "|| execution(* humanframe.backoffice..Admin*Controller.logout(..))")
private void checkAdminLog() {}
@Before(value = "checkAdminLog()")
private void beforecheckAdminLog(
JoinPoint joinPoint)throws Exception {
// ... дунд хэсэг орхигдсон (админ лог хадгалах логик) ...
}
}
5.5.2 Эрх шалгах
Цэс болон функцэд хандах эрхийг шалгахад AOP ашигладаг.
Үндсэн функц
- Цэсэнд хандах эрх шалгах
- Самбарын эрх шалгах
- Функцийн эрх шалгах
[Кодын байршил] humanframe.backoffice.aop.aspect.admin.AdminBbsAspect
@Aspect
@Order(1)
@Component
public class AdminBbsAspect {
@Autowired
private BbsSettingService bbsSettingService;
@Autowired
private MngrSession mngrSession;
// Админ эрх шалгах
@Pointcut("execution(* humanframe.backoffice..AdminBbsType*Controller.form(..))"
+ "|| execution(* humanframe.backoffice..AdminBbsType*Controller.list(..))"
+ "|| execution(* humanframe.backoffice..AdminBbsType*Controller.view(..))"
+ "|| execution(* humanframe.backoffice..AdminBbsType*Controller.action(..))"
+ "|| execution(* humanframe.backoffice..AdminBbsType*Controller.answer(..))")
private void checkAdminBbsAuth() {}
@Before(value = "checkAdminBbsAuth()")
private void beforeCheckAdminBbsAuth(
JoinPoint joinPoint)throws Exception {
// ... дунд хэсэг орхигдсон (эрх шалгах логик) ...
}
}
5.6 Интерсептор болон шүүлтүүр
HONGIKINGAN CMS нь интерсептор болон шүүлтүүр ашиглан хүсэлт боловсруулахын өмнө болон дараа нийтлэг ажлыг гүйцэтгэдэг. Энэ хэсэгт интерсептор болон шүүлтүүрийн бүтцийн талыг тайлбарлана. Аюулгүй байдлын дэлгэрэнгүй мэдээллийг 07 Аюулгүй байдлын удирдамж баримт бичгээс үзнэ үү.
5.6.1 Шүүлтүүрийн бүтэц
HONGIKINGAN CMS нь аюулгүй байдал болон өгөгдлийн урьдчилсан боловсруулалтыг сайжруулахын тулд төрөл бүрийн шүүлтүүрийг web.xml-д бүртгэж ашигладаг.
Шүүлтүүр нь сервлет контейнерийн түвшинд, web.xml-д тодорхойлсон дарааллаар бүх HTTP хүсэлт-д гинжин хэлбэрээр ажилладаг.
Үндсэн шүүлтүүр болон хэрэглэх зам
| Шүүлтүүрийн нэр | Хэрэглэх URL | Үүрэг/Тайлбар |
|---|---|---|
| CharacterEncodingFilter | /* |
Бүх хүсэлт/хариултын тэмдэгт кодчилолыг UTF-8-д нэгтгэх |
| HTMLTagFilter | /* |
Оролтын параметрээс аюултай HTML тагийг арилгах |
| CrossUrlScriptingFilter (XSS) | /* |
Cross-site scripting (XSS) довтолгооноос сэргийлэх |
| XSSWebFilter | /* |
Нэмэлт XSS аюулгүй байдлын шүүлтүүр (бодлогоор HTML болон JS аюултай элементийг шүүх) |
| MberLoginFilter | /* |
Spring Security (DelegatingFilterProxy) суурьтай нэвтрэх боловсруулалт |
| HumanFilter | /humanmst/* |
Админ хуудас тусгайлан: хандалтын хяналт, баталгаажуулалт/эрх шалгах |
Шүүлтүүрийн гинжний бүтэц
Клиентийн хүсэлт
↓
[CharacterEncodingFilter]
↓
[HTMLTagFilter]
↓
[CrossUrlScriptingFilter]
↓
[XSSWebFilter]
↓
[MberLoginFilter]
↓
[HumanFilter] (※ админ хуудас (/humanmst/*) хүсэлт үед л)
↓
Сервлет (DispatcherServlet гэх мэт)
Үйл ажиллагааны анхаарах зүйл
- Ихэнх шүүлтүүр бүх замд (
/*) хэрэглэгддэг бөгөөдHumanFilterнь админ хуудас (/humanmst/*) замд л хэрэглэгдэнэ. - Шүүлтүүрийн гүйцэтгэх дараалал нь web.xml-д бүртгэсэн дараалалтай ижил байдлаар ажилладаг.
- HTML/XSS шүүлтүүрийг давхарлан хэрэглэж оролтын утгын аюулгүй байдлыг дээд зэргээр хангана.
- Нэвтрэх/баталгаажуулалтын шүүлтүүрийг аюулгүй байдлын хувьд хойд дарааллд байрлуулна.
5.6.2 Интерсепторын бүтэц
HONGIKINGAN CMS нь HTTP хүсэлт боловсруулахын өмнө/дараа нийтлэг логикийг хэрэглэхийн тулд Spring MVC интерсептор (Interceptor) ашигладаг.
Үндсэн интерсептор нь dispatcher-servlet.xml-д бүртгэгдэж, доорх байдлаар өөр өөр зам болон үүрэгтэй.
Үндсэн интерсептор болон хэрэглэх зам
| Интерсепторын нэр | Хэрэглэх зам | Үүрэг/Тайлбар |
|---|---|---|
| CMSUriInterceptor | Бүх нийт (/), админ болон зарим үл хамаарах |
Сайтын URI хандалтын хяналт, шаардлагагүй хүсэлт хориглох гэх мэт |
| CMSAdminInterceptor | Админ тусгайлан (/humanmst/ гэх мэт) |
Админ хуудас хандалт тусгайлан, баталгаажуулалт болон эрх шалгах |
| DeviceResolverHandlerInterceptor | Бүх нийт | (Spring Mobile) Төхөөрөмжийн төрөл (гар утас/PC) ялгах зориулалт |
Интерсепторын гинжний бүтэц
Клиентийн хүсэлт
↓
[DeviceResolverHandlerInterceptor] (гар утас/PC ялгах)
↓
[CMSUriInterceptor] (сайтын URI хандалт удирдах, админ үл хамаарах)
↓
[CMSAdminInterceptor] (※ админ (/humanmst/ гэх мэт) хүсэлт үед л)
↓
Контроллер (Controller)
Үйл ажиллагааны анхаарах зүйл
Интерсепторын хэрэглэх/үл хамаарах зам нь dispatcher-servlet.xml-ийн <mvc:interceptor> тохиргоонд тулгуурладаг.