검색결과 리스트
글
struts2] struts2 + ibatis 활용한 게시판1-1
struts2 + ibatis 를 활용한 게시판
- struts2 framework 와 ibatis를 연동한 게시판 구축
- struts2 action클래스와 paging처리하는부분은 2페이지에 걸쳐 작성
1. 환경설정
- struts2,ibatis,oracle library 등록(web-inf/lib)
2. struts.xml
- aciton 등록
3. web.xml
- struts환경에서는 사용자가 action요청시 가장 먼저 FilterDispatcher가 호출되고 위에 그림처럼
배치관리자로 인해 struts.xml 파일과 struts.properties 파일이 자동으로 호출되게 된다
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
4. DaoService.java
- 데이타베이스 접속하기위한 DaoManager 를 반환하는 DaoService클래스 작성
- 싱글턴패턴으로 만들어서 하나의 DaoManager를 공유
* struts.xml
- 반드시 src 기본경로에 존재하여야 struts에서 인식할수있다.
- web.xml에서 등록한 필터가 읽혀진후 해당 xml문서가 읽혀진다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC '-//Apache Software Foundation//DTD Struts Configuration 2.0//EN'
'http://struts.apache.org/dtds/struts-2.0.dtd'>
<struts>
<package name="defalut" extends="struts-default" namespace="">
<action name="list" class="action.ListAction">
<result>/list.jsp</result>
</action>
</package>
</struts>
* DaoService.java
- DaoService는 한번만 읽혀져서 하나만 생성되어 DaoManager는 한개만 생성된다.
package dao;
import java.io.Reader;
import com.ibatis.common.resources.Resources;
import com.ibatis.dao.client.Dao;
import com.ibatis.dao.client.DaoManager;
import com.ibatis.dao.client.DaoManagerBuilder;
public class DaoService {
private static DaoManager daoManager;
private static DaoManager getDaoManager(){
String daoXmlResouce = "dao.xml"; //src폴더에 dao.xml
Reader reader = null;
if(daoManager ==null) //static으로 선언되어있기때문에 null 체크를 해서 null일경우만 생성
try {
reader = Resources.getResourceAsReader(daoXmlResouce); //dao.xml파일로부터 읽음
daoManager = DaoManagerBuilder.buildDaoManager(reader);
} catch (Exception e) {
e.printStackTrace();
}
return daoManager;
}
//실제 서버에서 dao객체가 필요할 경우 호출하는 메서드
public static Dao getDao(Class inter){
return getDaoManager().getDao(inter);
}
}
* dao.xml
- 사용하고자하는 dao interface 및 dao를 구현하고 있는 dao 를 명시
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE daoConfig PUBLIC "-//ibatis.apache.org//DTD DAO Configuration 2.0//EN" "http://ibatis.apache.org/dtd/dao-2.dtd">
<daoConfig>
<context id="sqlMap">
<transactionManager type="SQLMAP">
<property name="SqlMapConfigResource" value="config/SqlMapConfig.xml"/>
</transactionManager>
<dao interface="dao.Bbs" implementation="dao.BbsImpl"/>
</context>
</daoConfig>
* SqlMapConfig.xml
- 사용하는 database 환경설정이 필요한 파일이다(여기서는 oracle을 사용)
<!DOCTYPE sqlMapConfig PUBLIC '-//ibatis.apache.org/DTD SQL Map Config 2.0//EN'
'http://ibatis.apache.org/dtd/sql-map-config-2.dtd'>
<sqlMapConfig>
<properties resource="config/sqlMapConfig.properties" />
<transactionManager type="JDBC" commitRequired="false">
<dataSource type="SIMPLE">
<property name="JDBC.Driver" value="${driver}" /> //라이브러리(odbc14.jar)파일이 필요
<property name="JDBC.ConnectionURL" value="${url}" />
<property name="JDBC.Username" value="${user}" />
<property name="JDBC.Password" value="${pwd}" />
</dataSource>
</transactionManager>
<sqlMap resource="config/bbs.xml" />
</sqlMapConfig>
* SqlMapConfig.properties
- 보안을 위해 db접속정보를 따로 파일로 만들어둠
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:ORCL
user=SCOTT
pwd=TIGER
* Bbs.java(Interface)
- 사용자가 호출할수 있는 기능적요소들을 명시
package dao;
import java.util.ArrayList;
import vo.BbsVO;
public interface Bbs {
public ArrayList<BbsVO> getAllBbs();
}
* BbsImpl.java
- 위의 인터페이스를 구현하고 SqlMapDaoTemplate 를 상속받는 클래스
- 반드시 디폴트 생성자만 있으면 안되고 반드시 SqlMapDaoTemplate를 상속받고
DaoManager를 인자로 받는 생성자를 만들어야 한다.
- struts환경에서 여기에 정의된 메소드를 호출하게되면 결과를 받을수 있게 된다.
ex> getAllBbs()
* BbsVO.java
- DataBase에 있는 컬럼명과 동일한이름으로 멤버 변수로 정의
- 정의된 멤버변수의 setter/getter 메서드를 정의
* bbs.xml
- SqlMapConifg.xml 안에 <sqlMap>에 정의된 xml문서
- 이 안에 정의된 <select> 요소의 속성 id는 값은 BbsImple.java클래스의 queryForList("") 이안에
들어가는 인자값(String)과 동일해야 한다. ex> select id="selectAllBbs"
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC '-//ibatis.apache.org//DTD SQL Map 2.0//EN' 'http://ibatis.apache.org/dtd/sql-map-2.dtd'>
<sqlMap namespace="memo">
<typeAlias alias="bbsvo" type="vo.BbsVO"/>
<select id="selectAllBbs" resultClass="bbsvo">
select * from bbs_t order by idx desc
</select>
</sqlMap>
* ListAction.java
- struts 액션 클래스로서 ActionSupport를 상속
- pojo기반으로 사용하게되면 session처리하는데 어려움이 있기때문에 ActionSupport를 상속
- ListAction에서 ibatis DaoService에 정의된 메소드를 호출하게되면 해당 객체를 얻어낼수있다.
ex> Bbs bbs = (Bbs)DaoService.getDao(Bbs.class);
설정
트랙백
댓글
글
Java] java.lang.reflect.* 활용
*JSP 페이지로부터 form에 대한 값을 넘겨받아 useBean을 이용해서 값 저장
- jsp action 페이지에서 값을 저장후 reflect를 사용한 클래스 호출
<jsp:useBean id="vo" class="com.bbs.BbsVO">
<jsp:setProperty name="vo" property="*"/>
</jsp:useBean>
com.util.BeanExamer.survey(vo); // 자바클래스의 reflect를 이용한 클래스
* BeanExamer.java
package com.util;
import java.lang.ref.*;
import java.lang.reflect.*; // reflect를 사용하기 위한 import
import java.util.*;
public class BeanExamer {
public static void survey(Object obj){
Class clz = obj.getClass(); // 인자로 전달받은 vo객체를 통해 클래스를 얻어냄
Method[] methods = clz.getDeclaredMethods();
// 위에서 얻어낸 클래스를 통해 해당 클래스에 선언된 메소드들을 배열에 저장
ArrayList<Method> getMethods = new ArrayList<Method>(); // ArrayList에 메소드 타입으로 제너릭 설정
for(int i = 0; i < methods.length;i++){
/* 클래스에 선언된 메서드수만큼 loof를 시키고 get으로 시작하는 메서드만 ArrayList에 저장 */
if(methods[i].getName().startsWith("get") == true){
getMethods.add(methods[i]);
}
}
if(getMethods.size() <= 0){
return;
}
for(int i = 0; i < getMethods.size() ; i++){
Method m = getMethods.get(i);
try {
System.out.println(m.invoke(obj, null)); //invoke 메소드에 관한 내용은 아래내용을 참고
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
1.원형
Object invoke( Object obj, Object[] args )
2.사용
Class myclass = Class.forName( "package.name.MyClass" ); //특정 클래스의 클래스를 가져옴
Object myclassInstance = myclass.newInstance(); // 특정 클래스의 인스턴스 생성
Method[] methods = myclass.getMethods(); // 클래스의 메소드를 가져옴
// 메소드의 매개변수를 설정. 타입에 따라 Object 배열 초기화 코드의 내용이 틀려짐.
Object[] params = new Object[] { new Integer( value ) };
methods[0].invoke( myclassInstance, params ); //invoke함수는 클래스안에 메소드를 호출하게된다.
Method 클래스의 invoke 함수의 API 입니다. 보다시피 매개변수로 첫번째 메소드를 실행시킬 인스턴스나 클래스
를 넣어줘야 하고, 그 메소드의 매개변수를 Object 배열로 넣게 된다.
따라서 인트는 new Integer()로 감싸주거나 new BigDecimal()로 감싸주어 Object형으로 캐스팅 되게끔하고
String은 그 자체로서 Obejct형으로 캐스팅 되면서 Object[]배열로서 매겨변수로 들어가데 된다.
그러면 그 함수의 매개변수에 배열의 순서대로 넣어서 실행을 시킬수 있는것이다.
설정
트랙백
댓글
글
struts2] Download
Download
1. web.xml
- 필터등록(위에서 설정한 부분과 동일)
2. struts.properties
- struts환경설정 파일 (위에서 설정한 부분과 동일)
3. struts.xml
- result type에 결과를 stream으로 받기 때문에 stream으로 설정
- param 요소에 mimeType,원 자원의 길이, 컨텐츠헤더값, inputStream이름, 버퍼크기 설정
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC '-//Apache Software Foundation//DTD Struts Configuration 2.0//EN'
'http://struts.apache.org/dtds/struts-2.0.dtd'>
<struts>
<package name="defalut" extends="struts-default" namespace="">
<action name="fileList" class="ex1.FileListAction">
<result>/ex1/fileList.jsp</result>
</action>
<action name="fileDownload" class="ex1.FileDownLoadAction">
<result type="stream">
<param name="contentType">bynary/octet-stream</param> // mimeType
<param name="contentLength">${contentLength}</param> // 원자원의 길이
<param name="contentDisposition">${contentDisposition}</param>
<!-- 파일의 이름을 설정하기 위한 컨텐츠헤더값 지정-->
<param name="inputName">input</param> // inputStream 이름
<param name="bufferSize">4096</param> // 버퍼 크기
</result>
</action>
</package>
</struts>
4. fileList.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<h2>파일 목록</h2>
<s:property value="basePath"/>
<s:iterator value="fileList" status="stat">
/*
FileListAction 클래스로부터 받은 basePath를 param에 등록하고, fileName에 파일명을 등록
url에 해당 param을 등록하고 href요소에 url id를 맵핑시켜 사용자가 파일클릭시
fileDownload Action클래스를 수행하게하여 파일 다운로드가 수행되게 된다.
*/
<s:url id="download" action="fileDownload">
<s:param name="basePath" value="basePath"/>
<s:param name="fileName" >
<s:property value="fileList[#stat.index].name"/>
</s:param>
</s:url>
<li><s:a href="%{download}">
<s:property value="fileList[#stat.index].name"/>
</s:a>
</li>
</s:iterator>
5. FileListAction.java
- ActionSupport를 상속받는 action 클래스 등록
- properties파일에서 읽어올시 액션 파일명과 동일하게 작성하여 동일위치에 생성
package ex1;
import java.io.File;
import java.util.ArrayList;
import com.opensymphony.xwork2.ActionSupport;
public class FileListAction extends ActionSupport {
private ArrayList<File> fileList = new ArrayList<File>();
private String basePath;
// 필드에 선언된 setter/getter 메서드 정의
@Override
public String execute() throws Exception {
basePath = getText("path"); //프로퍼티파일에서 읽혀짐
//basePath = "D:/jspwork/struts2_FileUpload/WebContent/fileUpload";
/*
파일들이 저장되어 있는 폴더를 File객체로 생성한다.
이유는 그렇게 해야 그안에 있는 파일들을 가져와서 ArrayList에 저장할 수 있다.
내부의 모든 요소들을 반복하여 파일인지 아닌지를 비교하고 비교후 파일일경우 list에 추가
*/
File dir = new File(basePath);
File[] files = dir.listFiles();
if(files!=null && files.length>0)
for(File f : files)
if(f.isFile())
fileList.add(f);
return SUCCESS;
}
}
6. FileDownLoadAction.java
- 사용자가 파일명클릭시 수행되는 ActionClass(다운로드가 수행되는 ActionClass)
- struts.xml에 등록한것처럼 결과를 steam으로 전달하여 파일다운로드가 이루어짐
package ex1;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URLEncoder;
import com.opensymphony.xwork2.ActionSupport;
public class FileDownLoadAction extends ActionSupport{
private String basePath,fileName,contentType,contentDisposition;
private InputStream input;
private long contentLength;
// 필드에 선언된 setter/getter 메서드 정의
@Override
public String execute() throws Exception {
/* jsp페이지에서 taglib에 설정된 param name(value값)이 전달됨 */
String path = basePath + System.getProperty("file.separator") + fileName;
File f = new File(path);
setContentLength(f.length());
setContentDisposition("attachment; filename=" + URLEncoder.encode(fileName, "utf-8"));
setInput(new FileInputStream(path));
return SUCCESS;
}
}
설정
트랙백
댓글
글
struts2] multi upload
Multi Upload
1. web.xml 필터 등록
- singleupload에서 설정한것과 동일
2.struts.xml / struts.properties 설정
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC '-//Apache Software Foundation//DTD Struts Configuration 2.0//EN'
'http://struts.apache.org/dtds/struts-2.0.dtd'>
<struts>
<package name="defalut" extends="struts-default" namespace="">
<action name="multiUpload">
<result>/ex2/multiUpload.jsp</result>
</action>
<action name="multiUpload_ok" class="ex2.MultiUploadAction">
<result name="input">/ex2/multiUpload.jsp</result>
<result>/ex2/multiUploadResult.jsp</result>
</action>
</package>
</struts>
3. FileService.java
- 파일에 관한 처리가 이루어지는 클래스(저장폴더 생성 및 파일저장작업이 이루어지는 메서드정의)
package ex1;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileService {
/*
파일들이 저장될 폴더를 생성하는 메서드
폴더가 존재하지않을경우 폴더생성
*/
public void makeBasePath(String n){
File dir = new File(n);
if(!dir.exists())
dir.mkdirs();
}
/*
File, 저장경로(basePath),파일명을 인자로 받는 메서드
*/
public String saveFile(File file, String basePath, String fileName) throws Exception{
if(file == null || file.getName().equals("")||file.length()<1)
return null;
makeBasePath(basePath); // 저장될 폴더 생성! 폴더존재시 수행하지않음
String serverFullPath = basePath + System.getProperty("file.separator") + fileName; //파일명이 포함된 절대경로
FileInputStream fis = new FileInputStream(file); // 저장할 파일에 스트림 생성
/*
이제 위에 있는 스트림을 통해 읽은 자원을 저장할 스트림 생성
FileOutputStream은 경로만 존재한다면 그 위치에 파일이 있든 없든 무조건 파일을 만든다.
*/
FileOutputStream fos = new FileOutputStream(serverFullPath);
/*
위에서 생성한 빈파일이 서버측에 생성되었으므로 준비된 스트림을 통하여 채워넣는다.
*/
int readSize = 0 ;
byte[] buf = new byte[1024];
while((readSize = fis.read(buf))!=-1){
fos.write(buf, 0, readSize); //준비된 스트림을 통해 쓴다.
}
fos.close();
fis.close();
return serverFullPath;
}
}
4. multiUpload.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<s:actionerror/>
<font color="red"><s:fielderror/></font><!-- 유효성 검사 오류시 표현 -->
<s:form method="post" action="multiUpload_ok" enctype="multipart/form-data" theme="simple">
<b>멀티 파일 업로드 </b><hr>
File 1 : <s:file name="upload"/><br> //파일명을 동일하게 설정
File 2 : <s:file name="upload"/><br>
File 3 : <s:file name="upload"/><br>
<s:submit/>
</s:form>
5. MultiUploadAction.java
- ActionSupport 클래스를 상속받은 action클래스
- action클래스 (일반적인 setter/getter, execute()메소드로 구성됨)
- jsp페이지에서 action클래스가 불려질때 폼에서 전달된 값과 함께 자동적으로 execute()메서드가 호출됨
package ex2;
import java.io.File;
import com.opensymphony.xwork2.ActionSupport;
import ex1.FileService;
public class MultiUploadAction extends ActionSupport {
private File[] upload; // 멀티 업로드의 경우 배열로 받아 처리
private String[] uploadFileName,uploadContentType,serverFullPath;
public String execute() throws Exception{
serverFullPath = new String[upload.length];
//String basePath = getText("upload_folder"); //아래에 설정한 properties파일에서 내용을 가져옴
String basePath = "D:/jspwork/struts2_FileUpload/WebContent/fileUpload";
FileService fileService = new FileService();
for(int i =0 ; i<upload.length; i++){
serverFullPath[i] = fileService.saveFile(upload[i], basePath, uploadFileName[i]);
}
return SUCCESS;
}
}
6. MultiUploadAction.properties
- properties파일을 이용하여 값을 받아오게 설정할수 있다.
(action클래스명.xml 형식으로 작성시 struts에서 자동으로 호출됨)
upload_folder = D:/jspwork/struts2_FileUpload/WebContent/fileUpload
7. multiUploadResult.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>MultiUpload</title>
</head>
<body>
<h2> 멀티 파일 업로드 결과 </h2>
<s:iterator value="upload" status="stat">
/*
<s:property>선언시 자동적으로 action클래스에 getter메서드가 호출됨
배열로 받기 때문에 iterator를 이용하여 출력
*/
<li>파일 <s:property value="%{#stat.index+1}"/></li>
<li>컨텐츠 타입<s:property value="%{uploadContentType[#stat.index]}"/></li>
<li>로컬 파일 이름<s:property value="%{uploadFileName[#stat.index]}"/></li>
<li>서버 전체 경로<s:property value="%{serverFullPath[#stat.index]}"/></li>
<li>임시 파일 이름<s:property value="%{upload[#stat.index]}"/></li>
<hr>
</s:iterator>
</body>
</html>
설정
트랙백
댓글
글
struts2] single upload
Single Upload
1. web.xml 필터 등록
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2.struts.xml / struts.properties 설정
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC '-//Apache Software Foundation//DTD Struts Configuration 2.0//EN'
'http://struts.apache.org/dtds/struts-2.0.dtd'>
<struts>
<package name="defalut" extends="struts-default" namespace="">
<action name="singleUpload">
<result>/ex1/singleUpload.jsp</result>
</action>
<action name="singleUpload_ok" class="ex1.SingleUploadAction">
<result name="input">/ex1/singleUpload.jsp</result>
<result>/ex1/singleUploadResult.jsp</result>
</action>
</package>
</struts>
3. FileService.java
- 파일에 관한 처리가 이루어지는 클래스(저장폴더 생성 및 파일저장작업이 이루어지는 메서드정의)
package ex1;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class FileService {
/*
파일들이 저장될 폴더를 생성하는 메서드
폴더가 존재하지않을경우 폴더생성
*/
public void makeBasePath(String n){
File dir = new File(n);
if(!dir.exists())
dir.mkdirs();
}
/*
File, 저장경로(basePath),파일명을 인자로 받는 메서드
*/
public String saveFile(File file, String basePath, String fileName) throws Exception{
if(file == null || file.getName().equals("")||file.length()<1)
return null;
makeBasePath(basePath); // 저장될 폴더 생성! 폴더존재시 수행하지않음
String serverFullPath = basePath + System.getProperty("file.separator") + fileName; //파일명이 포함된 절대경로
FileInputStream fis = new FileInputStream(file); // 저장할 파일에 스트림 생성
/*
이제 위에 있는 스트림을 통해 읽은 자원을 저장할 스트림 생성
FileOutputStream은 경로만 존재한다면 그 위치에 파일이 있든 없든 무조건 파일을 만든다.
*/
FileOutputStream fos = new FileOutputStream(serverFullPath);
/*
위에서 생성한 빈파일이 서버측에 생성되었으므로 준비된 스트림을 통하여 채워넣는다.
*/
int readSize = 0 ;
byte[] buf = new byte[1024];
while((readSize = fis.read(buf))!=-1){
fos.write(buf, 0, readSize); //준비된 스트림을 통해 쓴다.
}
fos.close();
fis.close();
return serverFullPath;
}
}
4. singleUpload.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<s:actionerror/>
<font color="red"><s:fielderror/></font><!-- 유효성 검사 오류시 표현 -->
<s:form method="post" action="singleUpload_ok" enctype="multipart/form-data">
<b>파일업로드 </b><hr>
<s:file name="upload"/>
<s:submit/>
</s:form>
5. SingleUploadAction.java
- ActionSupport 클래스를 상속받은 action클래스
- action클래스 (일반적인 setter/getter, execute()메소드로 구성됨)
- jsp페이지에서 action클래스가 불려질때 폼에서 전달된 값과 함께 자동적으로 execute()메서드가 호출됨
package ex1;
import java.io.File;
import com.opensymphony.xwork2.ActionSupport;
public class SingleUploadAction extends ActionSupport {
private File upload;
private String uploadFileName,uploadContentType,serverFullPath;
public String execute() throws Exception {
String basePath = "D:/jspwork/struts2_FileUpload/WebContent/fileUpload";
FileService fileService = new FileService();
serverFullPath = fileService.saveFile(upload, basePath, uploadFileName);
return SUCCESS;
}
}
6. SingleUploadAction-validation.xml
- validation 설정을 하는 부분(action클래스명-validation.xml 형식으로 작성시 struts에서 자동으로 호출됨)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE validators PUBLIC '-//OpenSymphony Group //XWork Validator 1.0.2//EN' 'http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd'>
<validators>
<field name="upload">
<field-validator type="fieldexpression">
<param name="expression">
<![CDATA[
upload.length() > 0
]]>
</param>
<message>
업로드할 파일을 선택하십시오.
</message>
</field-validator>
</field>
</validators>
7. SingleUploadResult.jsp
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2> 단일 파일 업로드 결과 </h2>
<li>컨텐츠 타입<s:property value="uploadContentType"/></li>
<li>로컬 파일 이름<s:property value="uploadFileName"/></li>
<li>서버 전체 경로입<s:property value="serverFullPath"/></li>
<li>임시 파일 이름<s:property value="upload"/></li>
</body>
</html>
RECENT COMMENT