首页 > 代码库 > SSH系列:(26)投诉受理
SSH系列:(26)投诉受理
1、Hibernate逆向工程
1.1、CDM概念模型
这里虽然用了T_Complain,但是不建议这样做,因为后面生成JavaBean类时,会生成TComplain.java类,而不是Complain.java。
1.2、物理模型
1.3、生成的实体类和Hibernate映射文件
Complain.java
package com.rk.tax.entity; import java.sql.Timestamp; import java.util.HashSet; import java.util.Set; import java.util.Map; import java.util.HashMap; /** * TComplain entity. @author MyEclipse Persistence Tools */ public class Complain implements java.io.Serializable { // Fields private String compId; private String compCompany; private String compName; private String compMobile; private Boolean isAnonymous; private Timestamp compTime; private String compTitle; private String toCompName; private String toCompDept; private String compContent; private String state; private Set complainreplies = new HashSet(0); //状态 public static String COMPLAIN_STATE_UNDONE = "0"; public static String COMPLAIN_STATE_DONE = "1"; public static String COMPLAIN_STATE_INVALID = "2"; public static Map<String, String> COMPLAIN_STATE_MAP; static { COMPLAIN_STATE_MAP = new HashMap<String, String>(); COMPLAIN_STATE_MAP.put(COMPLAIN_STATE_UNDONE, "待受理"); COMPLAIN_STATE_MAP.put(COMPLAIN_STATE_DONE, "已受理"); COMPLAIN_STATE_MAP.put(COMPLAIN_STATE_INVALID, "已失效"); } // Constructors /** default constructor */ public Complain() { } public String getCompId() { return compId; } public void setCompId(String compId) { this.compId = compId; } public String getCompCompany() { return compCompany; } public void setCompCompany(String compCompany) { this.compCompany = compCompany; } public String getCompName() { return compName; } public void setCompName(String compName) { this.compName = compName; } public String getCompMobile() { return compMobile; } public void setCompMobile(String compMobile) { this.compMobile = compMobile; } public Boolean getIsAnonymous() { return isAnonymous; } public void setIsAnonymous(Boolean isAnonymous) { this.isAnonymous = isAnonymous; } public Timestamp getCompTime() { return compTime; } public void setCompTime(Timestamp compTime) { this.compTime = compTime; } public String getCompTitle() { return compTitle; } public void setCompTitle(String compTitle) { this.compTitle = compTitle; } public String getToCompName() { return toCompName; } public void setToCompName(String toCompName) { this.toCompName = toCompName; } public String getToCompDept() { return toCompDept; } public void setToCompDept(String toCompDept) { this.toCompDept = toCompDept; } public String getCompContent() { return compContent; } public void setCompContent(String compContent) { this.compContent = compContent; } public String getState() { return state; } public void setState(String state) { this.state = state; } public Set getComplainreplies() { return complainreplies; } public void setComplainreplies(Set complainreplies) { this.complainreplies = complainreplies; } }
知识点(1):
//状态 public static String COMPLAIN_STATE_UNDONE = "0"; public static String COMPLAIN_STATE_DONE = "1"; public static String COMPLAIN_STATE_INVALID = "2"; public static Map<String, String> COMPLAIN_STATE_MAP; static { COMPLAIN_STATE_MAP = new HashMap<String, String>(); COMPLAIN_STATE_MAP.put(COMPLAIN_STATE_UNDONE, "待受理"); COMPLAIN_STATE_MAP.put(COMPLAIN_STATE_DONE, "已受理"); COMPLAIN_STATE_MAP.put(COMPLAIN_STATE_INVALID, "已失效"); }
Complain.hbm.xml
注意:在生成的映射文件中去掉 catalog=”数据库名称”。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <!-- Mapping file autogenerated by MyEclipse Persistence Tools --> <hibernate-mapping> <class name="com.rk.tax.entity.Complain" table="t_complain"> <id name="compId" type="java.lang.String"> <column name="comp_id" length="32" /> <generator class="uuid.hex" /> </id> <property name="compCompany" type="java.lang.String"> <column name="comp_company" length="100" /> </property> <property name="compName" type="java.lang.String"> <column name="comp_name" length="20" /> </property> <property name="compMobile" type="java.lang.String"> <column name="comp_mobile" length="20" /> </property> <property name="isAnonymous" type="java.lang.Boolean"> <column name="is_anonymous" /> </property> <property name="compTime" type="java.sql.Timestamp"> <column name="comp_time" length="19" /> </property> <property name="compTitle" type="java.lang.String"> <column name="comp_title" length="200" not-null="true" /> </property> <property name="toCompName" type="java.lang.String"> <column name="to_comp_name" length="32" /> </property> <property name="toCompDept" type="java.lang.String"> <column name="to_comp_dept" length="100" /> </property> <property name="compContent" type="text"> <column name="comp_content"/> </property> <property name="state" type="java.lang.String"> <column name="state" length="1" /> </property> <set name="complainreplies" inverse="true" lazy="false" cascade="save-update" order-by="reply_time"> <key> <column name="comp_id" length="32" not-null="true" /> </key> <one-to-many class="com.rk.tax.entity.Complainreply" /> </set> </class> </hibernate-mapping>
知识点(1):
<property name="isAnonymous" type="java.lang.Boolean"> <column name="is_anonymous" /> </property>
知识点(2):
<property name="compTime" type="java.sql.Timestamp"> <column name="comp_time" length="19" /> </property>
知识点(3):
<property name="compContent" type="text"> <column name="comp_content"/> </property>
对应的类字段
private Boolean isAnonymous; private Timestamp compTime; private String compContent;
知识点(4):
<set name="complainreplies" inverse="true" lazy="false" cascade="save-update" order-by="reply_time"> <key> <column name="comp_id" length="32" not-null="true" /> </key> <one-to-many class="com.rk.tax.entity.Complainreply" /> </set>
其中
lazy="false" cascade="save-update" order-by="reply_time"
lazy="false"表示不使用懒加载,
cascade="save-update"表示级联保存、更新
order-by="reply-time"是指取出的数据按照reply-time排序。注意:reply_time是数据库的列的名称,这里也可以类的字段replyTime,但是类的字段replyTime与数据库的列名reply_time相比,类的字段replyTime可能在某些版本中存在问题,而数据库的列名reply_time更具有通用性。
Complainreply.java
package com.rk.tax.entity; import java.sql.Timestamp; /** * TComplainreply entity. @author MyEclipse Persistence Tools */ public class Complainreply implements java.io.Serializable { // Fields private String replyId; private Complain complain; private String replyer; private String replyDept; private Timestamp replyTime; private String replyContent; // Constructors /** default constructor */ public Complainreply() { } /** minimal constructor */ public Complainreply(Complain complain) { this.complain = complain; } /** full constructor */ public Complainreply(Complain complain, String replyer, String replyDept, Timestamp replyTime, String replyContent) { this.complain = complain; this.replyer = replyer; this.replyDept = replyDept; this.replyTime = replyTime; this.replyContent = replyContent; } public String getReplyId() { return replyId; } public void setReplyId(String replyId) { this.replyId = replyId; } public Complain getComplain() { return complain; } public void setComplain(Complain complain) { this.complain = complain; } public String getReplyer() { return replyer; } public void setReplyer(String replyer) { this.replyer = replyer; } public String getReplyDept() { return replyDept; } public void setReplyDept(String replyDept) { this.replyDept = replyDept; } public Timestamp getReplyTime() { return replyTime; } public void setReplyTime(Timestamp replyTime) { this.replyTime = replyTime; } public String getReplyContent() { return replyContent; } public void setReplyContent(String replyContent) { this.replyContent = replyContent; } }
Complainreply.hbm.xml
注意:在生成的映射文件中去掉 catalog=”数据库名称”。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <!-- Mapping file autogenerated by MyEclipse Persistence Tools --> <hibernate-mapping> <class name="com.rk.tax.entity.Complainreply" table="t_complainreply"> <id name="replyId" type="java.lang.String"> <column name="reply_id" length="32" /> <generator class="uuid.hex" /> </id> <many-to-one name="complain" class="com.rk.tax.entity.Complain" fetch="select"> <column name="comp_id" length="32" not-null="true" /> </many-to-one> <property name="replyer" type="java.lang.String"> <column name="replyer" length="20" /> </property> <property name="replyDept" type="java.lang.String"> <column name="reply_dept" length="100" /> </property> <property name="replyTime" type="java.sql.Timestamp"> <column name="reply_time" length="19" /> </property> <property name="replyContent" type="java.lang.String"> <column name="reply_content" length="300" /> </property> </class> </hibernate-mapping>
2、从dao到action
dao->service->action->config
2.1、dao层
ComplainDao.java
package com.rk.tax.dao; import com.rk.core.dao.BaseDao; import com.rk.tax.entity.Complain; public interface ComplainDao extends BaseDao<Complain> { }
ComplainDaoImpl.java
package com.rk.tax.dao.impl; import com.rk.core.dao.impl.BaseDaoImpl; import com.rk.tax.dao.ComplainDao; import com.rk.tax.entity.Complain; public class ComplainDaoImpl extends BaseDaoImpl<Complain> implements ComplainDao { }
2.2、service层
ComplainService.java
package com.rk.tax.service; import com.rk.core.service.BaseService; import com.rk.tax.entity.Complain; public interface ComplainService extends BaseService<Complain> { }
ComplainServiceImpl.java
package com.rk.tax.service.impl; import java.util.Calendar; import java.util.List; import javax.annotation.Resource; import org.springframework.stereotype.Service; import com.rk.core.service.Impl.BaseServiceImpl; import com.rk.core.utils.QueryHelper; import com.rk.tax.dao.ComplainDao; import com.rk.tax.entity.Complain; import com.rk.tax.service.ComplainService; @Service("complainService") public class ComplainServiceImpl extends BaseServiceImpl<Complain> implements ComplainService { private ComplainDao complainDao; @Resource public void setComplainDao(ComplainDao complainDao) { setBaseDao(complainDao); this.complainDao = complainDao; } }
2.3、action层
ComplainAction.java
package com.rk.tax.action; import java.net.URLDecoder; import java.sql.Timestamp; import java.util.Date; import javax.annotation.Resource; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateUtils; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import com.opensymphony.xwork2.ActionContext; import com.rk.core.action.BaseAction; import com.rk.core.utils.QueryHelper; import com.rk.tax.entity.Complain; import com.rk.tax.entity.Complainreply; import com.rk.tax.service.ComplainService; @Controller("complainAction") @Scope("prototype") public class ComplainAction extends BaseAction { /*****1、业务数据*****/ private Complain complain; private String startTime; private String endTime; private String state; private Complainreply reply; /*****2、业务实现类*****/ @Resource private ComplainService complainService; /*****3、响应页面操作*****/ //列表 public String listUI(){ //加载状态集合 ActionContext.getContext().getContextMap().put("complainStateMap", Complain.COMPLAIN_STATE_MAP); try { QueryHelper queryHelper = new QueryHelper(Complain.class, "c"); if(StringUtils.isNotBlank(startTime)){//查询开始时间之后的投诉数据 startTime = URLDecoder.decode(startTime, "utf-8"); queryHelper.addCondition("c.compTime >= ?", DateUtils.parseDate(startTime+":00", "yyyy-MM-dd HH:mm:ss")); } if(StringUtils.isNotBlank(endTime)){//查询结束时间之前的投诉数据 endTime = URLDecoder.decode(endTime, "utf-8"); queryHelper.addCondition("c.compTime <= ?", DateUtils.parseDate(endTime+":00", "yyyy-MM-dd HH:mm:ss")); } if(StringUtils.isNotBlank(searchContent)){ searchContent = URLDecoder.decode(searchContent, "utf-8"); queryHelper.addCondition("c.compTitle like ?", "%" + searchContent + "%"); } if(StringUtils.isNotBlank(state)){ queryHelper.addCondition("c.state=?", state); } //按照状态升序排序 queryHelper.addOrderByProperty("c.state", QueryHelper.ORDER_BY_ASC); //按照投诉时间升序排序 queryHelper.addOrderByProperty("c.compTime", QueryHelper.ORDER_BY_ASC); pageResult = complainService.getPageResult(queryHelper, pageNo, pageSize); } catch (Exception e) { e.printStackTrace(); } return "listUI"; } //跳转到受理页面 public String dealUI(){ //加载状态集合 ActionContext.getContext().getContextMap().put("complainStateMap", Complain.COMPLAIN_STATE_MAP); if(complain != null && StringUtils.isNotBlank(complain.getCompId())){ complain = complainService.findById(complain.getCompId()); } return "dealUI"; } public String deal(){ if(complain != null && StringUtils.isNotBlank(complain.getCompId())){ Complain temp = complainService.findById(complain.getCompId()); //1、更新投诉的状态为 已受理 if(!Complain.COMPLAIN_STATE_DONE.equals(temp.getState())){ temp.setState(Complain.COMPLAIN_STATE_DONE); } //2、保存回复信息 if(reply != null){ reply.setComplain(temp); /** * 在后台设置时间,有两点好处: * (1)在前台JSP页面,不需要再提供相应的表单域 * (2)有两个时间:JSP前台页面生成的时间、服务器保存数据的时间,后者更准确一些 */ reply.setReplyTime(new Timestamp(new Date().getTime())); temp.getComplainreplies().add(reply); } complainService.update(temp); } return "list"; } // Properties public Complain getComplain() { return complain; } public void setComplain(Complain complain) { this.complain = complain; } public String getStartTime() { return startTime; } public void setStartTime(String startTime) { this.startTime = startTime; } public String getEndTime() { return endTime; } public void setEndTime(String endTime) { this.endTime = endTime; } public String getState() { return state; } public void setState(String state) { this.state = state; } public Complainreply getReply() { return reply; } public void setReply(Complainreply reply) { this.reply = reply; } }
知识点(1):级联 保存、更新
在deal()方法中
Complain temp = complainService.findById(complain.getCompId()); //1、更新投诉的状态为 已受理 if(!Complain.COMPLAIN_STATE_DONE.equals(temp.getState())){ temp.setState(Complain.COMPLAIN_STATE_DONE); } //2、保存回复信息 if(reply != null){ reply.setComplain(temp); /** * 在后台设置时间,有两点好处: * (1)在前台JSP页面,不需要再提供相应的表单域 * (2)有两个时间:JSP前台页面生成的时间、服务器保存数据的时间,后者更准确一些 */ reply.setReplyTime(new Timestamp(new Date().getTime())); temp.getComplainreplies().add(reply); } complainService.update(temp);
最后只调用complainService.update(temp),而temp是Complain类型的变量,而真正想要保存的的reply变量,这是通过级联保存(更新)实现的,Complain.hbm.xml中设置了cascade="save-update"
<set name="complainreplies" inverse="true" lazy="false" cascade="save-update" order-by="reply_time"> <key> <column name="comp_id" length="32" not-null="true" /> </key> <one-to-many class="com.rk.tax.entity.Complainreply" /> </set>
2.4、config
entity层的配置就是*.hbm.xml文件
dao层的配置是将dao类加入到Spring的IOC容器中
service层的配置是将service类加入到Spring的IOC容器中
action层的配置是将action类加入到Spring的IOC容器中,并在struts中对action进行url映射
最后记得将spring和struts的配置都汇总到applicationContext.xml和struts.xml文件中
3、JSP页面
listUI.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <%@include file="/common/header.jsp"%> <title>投诉受理管理</title> <script type="text/javascript" src="http://www.mamicode.com/${basePath}/js/datepicker/WdatePicker.js"></script> <script type="text/javascript"> var list_url = "${basePath}/tax/complain_listUI.action"; function doAnnualStatistic(){ // TODO } function doDeal(id){ document.forms[0].action = "${basePath}/tax/complain_dealUI.action?complain.compId="+id; document.forms[0].submit(); } </script> </head> <body class="rightBody"> <form name="form1" action="" method="post"> <div class="p_d_1"> <div class="p_d_1_1"> <div class="content_info"> <div class="c_crumbs"><div><b></b><strong>投诉受理管理</strong></div> </div> <div class="search_art"> <li> 投诉标题:<s:textfield name="searchContent" cssClass="s_text" cssStyle="width:160px;"/> </li> <li> 投诉时间:<s:textfield id="startTime" name="startTime" cssClass="s_text" cssStyle="width:160px;" readonly="true" onfocus="WdatePicker({‘skin‘:‘whyGreen‘,‘dateFmt‘:‘yyyy-MM-dd HH:mm‘})"/> - <s:textfield id="endTime" name="endTime" cssClass="s_text" cssStyle="width:160px;" readonly="true" onfocus="WdatePicker({‘skin‘:‘whyGreen‘,‘dateFmt‘:‘yyyy-MM-dd HH:mm‘})"/> </li> <li> 状态:<s:select name="state" list="#complainStateMap" headerKey="" headerValue="http://www.mamicode.com/全部"/> </li> <li><input type="button" class="s_button" value="http://www.mamicode.com/搜 索" onclick="doSearch()"/></li> <li style="float:right;"> <input type="button" value="http://www.mamicode.com/统计" class="s_button" onclick="doAnnualStatistic()"/> </li> </div> <div class="t_list" style="margin:0px; border:0px none;"> <table width="100%" border="0"> <tr class="t_tit"> <td align="center">投诉标题</td> <td width="120" align="center">被投诉部门</td> <td width="120" align="center">被投诉人</td> <td width="140" align="center">投诉时间</td> <td width="100" align="center">受理状态</td> <td width="100" align="center">操作</td> </tr> <s:iterator value="http://www.mamicode.com/pageResult.items" status="st"> <tr <s:if test="#st.odd"> bgcolor="f8f8f8" </s:if> > <td align="center"><s:property value="http://www.mamicode.com/compTitle"/></td> <td align="center"><s:property value="http://www.mamicode.com/toCompDept"/></td> <td align="center"><s:property value="http://www.mamicode.com/toCompName"/></td> <td align="center"><s:date name="compTime" format="yyyy-MM-dd HH:mm"/></td> <td align="center"><s:property value="http://www.mamicode.com/#complainStateMap[state]"/></td> <td align="center"> <a href="javascript:doDeal(‘<s:property value=‘compId‘/>‘)">受理</a> </td> </tr> </s:iterator> </table> </div> </div> <%@include file="/common/pageNavigator.jsp" %> </div> </div> </form> </body> </html>
知识点(1):WDatePicker
<script type="text/javascript" src="http://www.mamicode.com/${basePath}/js/datepicker/WdatePicker.js"></script>
<s:textfield id="startTime" name="startTime" cssClass="s_text" cssStyle="width:160px;" readonly="true" onfocus="WdatePicker({‘skin‘:‘whyGreen‘,‘dateFmt‘:‘yyyy-MM-dd HH:mm‘})"/>
知识点(2):<s:select>
<s:select name="state" list="#complainStateMap" headerKey="" headerValue="http://www.mamicode.com/全部"/>
dealUI.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <%@include file="/common/header.jsp"%> <title>投诉受理管理</title> </head> <body class="rightBody"> <form id="form" name="form" action="${basePath}/tax/complain_deal.action" method="post" enctype="multipart/form-data"> <div class="p_d_1"> <div class="p_d_1_1"> <div class="content_info"> <div class="c_crumbs"><div><b></b><strong>投诉受理管理</strong> - 投诉受理</div></div> <div class="tableH2">投诉详细信息<span style="color:red;">(已受理)</span></div> <table id="baseInfo" width="100%" align="center" class="list" border="0" cellpadding="0" cellspacing="0" > <tr><td colspan="2" align="center">投诉人信息</td></tr> <tr> <td class="tdBg" width="250px">是否匿名投诉:</td> <td><s:property value="http://www.mamicode.com/complain.isAnonymous?‘匿名投诉‘:‘非匿名投诉‘"/></td> </tr> <tr> <td class="tdBg">投诉人单位:</td> <td> <s:if test="!complain.isAnonymous"> <s:property value="http://www.mamicode.com/complain.compCompany"/> </s:if> </td> </tr> <tr> <td class="tdBg">投诉人姓名:</td> <td> <s:if test="!complain.isAnonymous"> <s:property value="http://www.mamicode.com/complain.compName"/> </s:if> </td> </tr> <tr> <td class="tdBg">投诉人手机:</td> <td> <s:if test="!complain.isAnonymous"> <s:property value="http://www.mamicode.com/complain.compMobile"/> </s:if> <s:elseif test="complain.compMobile.length() > 10"> <s:property value="http://www.mamicode.com/complain.compMobile.substring(0,3) + ‘****‘ + complain.compMobile.substring(7,11)"/> </s:elseif> <s:else> <s:property value="http://www.mamicode.com/complain.compMobile"/> </s:else> </td> </tr> <tr><td colspan="2" align="center">投诉信息</td></tr> <tr> <td class="tdBg">投诉时间:</td> <td> <s:date name="complain.compTime" format="yyyy-MM-dd HH:mm"/> </td> </tr> <tr> <td class="tdBg">被投诉部门:</td> <td><s:property value="http://www.mamicode.com/complain.toCompDept"/></td> </tr> <tr> <td class="tdBg">被投诉人:</td> <td><s:property value="http://www.mamicode.com/complain.toCompName"/></td> </tr> <tr> <td class="tdBg">投诉标题:</td> <td><s:property value="http://www.mamicode.com/complain.compTitle"/></td> </tr> <tr> <td class="tdBg">投诉内容:</td> <td><s:property value="http://www.mamicode.com/complain.compContent" escape="false"/></td> </tr> <tr><td colspan="2" align="center">受理信息</td></tr> <tr> <td colspan="2"> <s:iterator value="http://www.mamicode.com/complain.complainreplies" status="st"> <fieldset style="border: solid 1px #c0c0c0;margin-top:5px;"><legend style="color:green;font-weight:bold;">回复<s:property value="http://www.mamicode.com/#st.count"/> </legend> <div style="width:100%; text-align:center;color:#ccc;maring-top:5px;"> 回复部门:<s:property value="http://www.mamicode.com/replyDept"/> 回复人:<s:property value="http://www.mamicode.com/replyer"/> 回复时间:<s:date name="replyTime" format="yyyy-MM-dd HH:mm"/> </div> <div style="width:100%;maring-top:10px;font-size:13px;padding-left:5px;"> <s:property value="http://www.mamicode.com/replyContent"/> </div> </fieldset> </s:iterator> </td> </tr> <tr><td colspan="2" align="center">受理操作</td></tr> <tr> <td class="tdBg">回复部门:</td> <td> <s:property value="http://www.mamicode.com/#session.SYS_USER.dept"/> <s:hidden name="reply.replyDept" value="http://www.mamicode.com/%{#session.SYS_USER.dept}"/> </td> </tr> <tr> <td class="tdBg">回复人:</td> <td> <s:property value="http://www.mamicode.com/#session.SYS_USER.name"/> <s:hidden name="reply.replyer" value="http://www.mamicode.com/%{#session.SYS_USER.name}"/> </td> </tr> <tr> <td class="tdBg" width="200px">回复内容:</td> <td><s:textarea name="reply.replyContent" cols="90" rows="8" /></td> </tr> </table> <s:hidden name="complain.compId"/> <div class="tc mt20"> <input type="submit" class="btnB2" value="http://www.mamicode.com/保存" /> <input type="button" onclick="javascript:history.go(-1)" class="btnB2" value="http://www.mamicode.com/返回" /> </div> </div></div></div> </form> </body> </html>
知识点(1):OGNL字符中长度判断 和 拼接
<s:elseif test="complain.compMobile.length() > 10"> <s:property value="http://www.mamicode.com/complain.compMobile.substring(0,3) + ‘****‘ + complain.compMobile.substring(7,11)"/> </s:elseif>
知识点(2):<s:date>
<s:date name="complain.compTime" format="yyyy-MM-dd HH:mm"/>
知识点(3):<s:property>和<s:hidden> 似乎对OGNL的支持不同
<s:property value="http://www.mamicode.com/#session.SYS_USER.name"/> <s:hidden name="reply.replyer" value="http://www.mamicode.com/%{#session.SYS_USER.name}"/>
SSH系列:(26)投诉受理