一、参与调查的流程
单击导航栏上的“参与调查”按钮->EntrySurveyAction做出相应,找到所有的Survey对象并转发到显示所有survey对象的页面上供用户选择->用户单击其中一个调查进入调查页面->页面提供上一页、下一页、退出、保存等按钮供用户选择->用户单击退出直接返回到显示所有Survey对象的页面上去或者单击提交完成调查返回到参与调查的页面上去。
二、显示所有调查
请求的方法是Action中的toSurveyPage方法
1 public String toSurveyPage() throws Exception{ 2 //重新获取survey对象 3 this.model=this.surveyService.getModelById(this.model.getSurveyId()); 4 float requestPage; 5 //得到请求页,实际上就是orderNo 6 if(parameters.get("requestPage")!=null){ 7 requestPage=Float.parseFloat(parameters.get("requestPage")[0]); 8 }else{ 9 requestPage=this.model.getMinOrderNo(); 10 } 11 Page responsePage=this.surveyService.getResponsePage(this.model,requestPage); 12 ServletActionContext.getContext().put("page",responsePage); 13 14 //将两个参数保存到Session中去 15 this.session.put(this.CURRENT_SURVEY, this.model); 16 this.session.put(ALL_PARAMETERS, new HashMap<String,Map<String,String[]>>()); 17 return "surveyPage"; 18 }
这里需要注意的是上面代码中的粗体部分,该部分实际上是为了方便调用以后回显功能、保存答案功能使用的。
显示所有调查是以图表配以文字的形式进行说明的,使用的图标是之前说过的上传的logo,如果没有设置logo,则使用默认的logo。
1 <s:iterator value="%{#surveys}" var="survey"> 2 <s:a cssClass="survey" action="EntrySurveyAction_toSurveyPage.action" namespace="/"> 3 <s:param name="surveyId" value="#survey.surveyId"></s:param> 4 <img width="200px" alt="<s:property value='%{#survey.title}'/>" src='<s:property value="getLogoPath(#survey.logoPath)"/>'/><br/> 5 <s:property value="#survey.title"/> 6 </s:a> 7 </s:iterator>
这里还需要调用Action中的一个方法getLogoPath,该方法用于获取logo的时机url地址,方法如下:
1 //判断logo是否存在如果存在返回路径,如果不存在,返回默认路径 2 public String getLogoPath(String logoPath){ 3 System.out.println(logoPath); 4 if(logoPath!=null){ 5 String realPath=this.servletConetxt.getRealPath(logoPath); 6 File file=new File(realPath); 7 if(file.exists()){ 8 return servletConetxt.getContextPath()+logoPath; 9 } 10 } 11 return servletConetxt.getContextPath()+"/upload/defaultLogo.jpg"; 12 }
三、参与调查的页面设计
参与调查的页面一直是重用的,无论点击下一步还是上一步,返回的页面还是这一个页面,这肯定是请求了一个参数,这个参数就是页面的标识id。Action根据请求的id获取该Page对象的所有属性值,并将该Page对象返回到前端显示。根据该page的orderNo属性判断是否还有上一页、下一页并根据不同的结果显示出上一步、下一步、提交按钮,但是在每一页上都有“退出”按钮。
上一篇笔记中提到的Page兑现的minOrderNo和maxOrderNo就是在这个时候用到的。
导航的代码使用strus2标签控制判断是否显示上一页、下一页、完成这三个按钮:
1 <!-- 导航栏界面的问题,包括上一题、下一题、退出按钮的设计 --> 2 <div 3 style="width: 30%; margin: 0 auto; text-align: center; margin-top: 30px; font-size: 20px;"> 4 <s:if test="#page.orderNo!=#page.survey.minOrderNo"> 5 <input type="submit" 6 value="<s:property value='#page.survey.submit_pre'/>" 7 name="submit_pre" /> 8 </s:if> 9 <s:if test="#page.orderNo!=#page.survey.maxOrderNo"> 10 <input type="submit" 11 value="<s:property value='#page.survey.submit_next'/>" 12 name="submit_next"> 13 </s:if> 14 <s:if test="#page.orderNo==#page.survey.maxOrderNo"> 15 <%-- <input type="submit" 16 value="<s:property value='#page.survey.submit_done'/>" 17 name="submit_done"> --%> 18 <s:submit name="submit_done" value="%{#page.survey.submit_done}"></s:submit> 19 </s:if> 20 <input type="submit" 21 value="<s:property value='#page.survey.submit_exit'/>" 22 name="submit_exit"> 23 </div>
关键是Survey对象的minOrderNo和maxOrderNo是什么时候赋值的,又是怎么获取到的。这里使用了hibernate的功能。在Survey的hibernate映射文件中使用一种新型的配置方式解决该问题。
<property name="maxOrderNo" type="float"> <formula>(select max(p.orderNo) from page p where p.surveyId=surveyId)</formula> </property> <property name="minOrderNo" type="float"> <formula>(select min(p.orderNo) from page p where p.surveyId=surveyId)</formula> </property>
这是根据数据库中的相应信息将查询结果赋值到Bean对象中相关属性的一种方法。这些属性在数据库中并没有相关字段,但是在前端页面中会使用到。formula(表达式)标签中使用的是原生的sql语句。
其余问题的显示可以直接拷贝设计调查页面中的设计代码稍微修改一下就好了。
参与调查页面的完整代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 <%@ page language="java" pageEncoding="utf-8"%> 2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 3 <html> 4 <head> 5 <!-- 6 天哪,简直不能认了,必须将struts2标签全部换成html标签才能正常 7 否则不能正常解析动态指定的name属性,怪不得那个老师不使用struts2标签,我还以为他是傻X呢 8 9 最后一个问题:下拉列表类型的问题,是不是必须要有个默认值才行,不是默认选择第一个吗。 10 但是通过统计答案的过程中发现在下拉列表框中如果没有给他一个默认值的话,就默认没有选择。 11 --> 12 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 13 <title>Insert title here</title> 14 <link rel="stylesheet" 15 href="${pageContext.servletContext.contextPath}/css/header.css" 16 type="text/css"> 17 <style type="text/css"> 18 table { 19 border: 1px solid black; 20 border-collapse: collapse; 21 width: 100%; 22 } 23 tr td { 24 border: 1px solid black; 25 border-collapse: collapse; 26 } 27 28 a { 29 color: gray; 30 text-decoration: none; 31 } 32 33 a:HOVER { 34 color: red; 35 } 36 37 .tdHL { 38 text-align: left; 39 border-width: 0px; 40 } 41 42 .tdHR { 43 text-align: right; 44 border-width: 0px; 45 } 46 47 .pageTitle { 48 background-color: #CCF; 49 } 50 51 .questionTitle { 52 background-color: #CCC; 53 } 54 </style> 55 </head> 56 <body> 57 <%@ include file="/header.jsp"%> 58 这里是答题界面! 59 <s:form namespace="/" action="EntrySurveyAction_doEntrySurvey.action"> 60 <div> 61 <s:set value="%{#page.survey.surveyId}" name="id" /> 62 <!-- 当前页的页码 --> 63 <s:hidden name="pageId" value="%{#page.pageId}"></s:hidden> 64 <table> 65 <s:set var="pId" value="%{#page.pageId}"></s:set> 66 <tr> 67 <td> 68 <table style="display: inline-table;"> 69 <tr class="pageTitle"> 70 <!-- 页面标题 --> 71 <td colspan="2" width="40%" class="tdHL"><s:property 72 value="%{#page.title}" /></td> 73 </tr> 74 <tr> 75 <td colspan="2"> 76 <table style="display: inline-table;"> 77 <tr> 78 <td width="20px"></td> 79 <td> 80 <!-- 迭代问题的集合 --> 81 <table style="display: inline-table;"> 82 <s:iterator value="%{#page.questions}" var="question"> 83 <s:set var="qid" value="%{#question.questionId}"></s:set> 84 <!-- 问题题干 --> 85 <tr class="questionTitle"> 86 <td colspan="2" class="tdHL"><s:property 87 value="%{#question.title}" /></td> 88 </tr> 89 <!-- 问题主体,主要涉及的问题就是问题的分类 --> 90 <tr> 91 <td colspan="2"> 92 <!-- 定义变量,为当前类型的题型 --> <s:set 93 value="%{#question.questionType}" var="qt"></s:set> <!-- 第一种题型:带有单选框或者复选框的 94 题目标识就是题号小于4,0-3 95 --> <s:if test="#qt lt 4"> 96 <s:iterator value="#question.optionTextArr" status="st"> 97 <input name="q<s:property value='#qid'/>" 98 value='<s:property value="#st.index"/>' 99 type='<s:property value="#qt<2?'radio':'checkbox'"/>' 100 <s:property value="setTag(#pId+'','q'+#qid,#st.index,'checked')"/> 101 > 102 <s:property /> 103 <s:if test="#qt==1 || #qt==3"> 104 <br /> 105 </s:if> 106 </s:iterator> 107 <!-- 处理other的情况 --> 108 <s:if test="#question.other"> 109 <input name="q<s:property value='#qid'/>" 110 value="other" 111 <s:property value="setTag(#pId+'','q'+#qid,'other','checked')"/> 112 type='<s:property value="#qt<2?'radio':'checkbox'"/>'>其它 113 <s:if test="#question.otherType==1"> 114 <input type="text" name='q<s:property value="#qid"/>other' 115 <s:property value="setText(#pId,'q'+#qid+'other')"/> 116 /> 117 </s:if> 118 <s:elseif test="#question.otherType==2"> 119 <select name="q<s:property value='#qid'/>other"> 120 <s:iterator value="#question.otherSelectOptionArr" status="st"> 121 <option 122 <s:property value="setTag(#pId+'','q'+#qid+'other',#st.index,'selected')"/> 123 value='<s:property value="#st.index"/>'> 124 <s:property/> 125 </option> 126 </s:iterator> 127 </select> 128 </s:elseif> 129 </s:if> 130 </s:if> 131 <!-- 第二种题型,是下拉列表类型的题型 --> 132 <s:elseif test="#qt==4"> 133 <select name="q<s:property value='#qid'/>"> 134 <s:iterator value="#question.optionTextArr" status="st"> 135 <option 136 <s:property value="setTag(#pId+'','q'+#qid,#st.index,'selected')"/> 137 value='<s:property value="#st.index"/>'><s:property/></option> 138 </s:iterator> 139 </select> 140 </s:elseif> 141 <s:elseif test="#qt==5"> 142 <input type="text" name="q<s:property value='#qid'/>" 143 <s:property value="setText(#pId,'q'+#qid)"/> 144 /> 145 </s:elseif> <!-- 第三种题型,矩阵问题,6,7,8 --> <s:else> 146 <table style="display: inline-table;"> 147 <!-- 列头 --> 148 <tr> 149 <td></td> 150 <s:iterator value="#question.matrixColTitleArr"> 151 <td><s:property /></td> 152 </s:iterator> 153 </tr> 154 <!-- 输出N多行 --> 155 <s:iterator value="#question.matrixRowTitleArr" 156 status="rowst"> 157 <tr> 158 <td><s:property /></td> 159 <s:iterator value="#question.matrixColTitleArr" 160 status="colst"> 161 <td><s:if test="#qt==6"> 162 <!-- 对于矩阵式单选按钮的问题,必须将每一行视为一个单独的问题 --> 163 <input type="radio" 164 value='<s:property value="#rowst.index+'_'+#colst.index"/>' 165 name="q<s:property value='#qid+"_"+#rowst.index'/>" 166 <s:property value="setTag(#pId+'','q'+#qid+'_'+#rowst.index,#rowst.index+'_'+#colst.index,'checked')"/> 167 > 168 </s:if> <s:elseif test="#qt==7"> 169 <input type="checkbox" 170 value='<s:property value="#rowst.index+'_'+#colst.index"/>' 171 name="q<s:property value='#qid'/>" 172 <s:property value="setTag(#pId+'','q'+#qid,#rowst.index+'_'+#colst.index,'checked')"/> 173 > 174 </s:elseif> <s:elseif test="#qt==8"> 175 <select name="q<s:property value='#qid'/>"> 176 <s:iterator 177 status="selst" 178 value="#question.matrixSelectOptionArr"> 179 <option value='<s:property value="#rowst.index+'_'+#colst.index+'_'+#selst.index"/>' 180 <s:property value="setTag(#pId+'','q'+#qid,#rowst.index+'_'+#colst.index+'_'+#selst.index,'selected')"/> 181 > 182 <s:property /> 183 </option> 184 </s:iterator> 185 </select> 186 </s:elseif></td> 187 </s:iterator> 188 </tr> 189 </s:iterator> 190 </table> 191 </s:else> 192 </td> 193 </tr> 194 </s:iterator> 195 </table> 196 </td> 197 </tr> 198 </table> 199 </td> 200 </tr> 201 </table> 202 </td> 203 </tr> 204 </table> 205 <!-- 导航栏界面的问题,包括上一题、下一题、退出按钮的设计 --> 206 <div 207 style="width: 30%; margin: 0 auto; text-align: center; margin-top: 30px; font-size: 20px;"> 208 <s:if test="#page.orderNo!=#page.survey.minOrderNo"> 209 <input type="submit" 210 value="<s:property value='#page.survey.submit_pre'/>" 211 name="submit_pre" /> 212 </s:if> 213 <s:if test="#page.orderNo!=#page.survey.maxOrderNo"> 214 <input type="submit" 215 value="<s:property value='#page.survey.submit_next'/>" 216 name="submit_next"> 217 </s:if> 218 <s:if test="#page.orderNo==#page.survey.maxOrderNo"> 219 <%-- <input type="submit" 220 value="<s:property value='#page.survey.submit_done'/>" 221 name="submit_done"> --%> 222 <s:submit name="submit_done" value="%{#page.survey.submit_done}"></s:submit> 223 </s:if> 224 <input type="submit" 225 value="<s:property value='#page.survey.submit_exit'/>" 226 name="submit_exit"> 227 </div> 228 </div> 229 </s:form> 230 </body> 231 </html>
四、答案回显
到三未知,已经能够实现页面的显示并通过上一页、下一页翻页了。下一步实现答案的回显。所谓的答案回显就是单击上一步按钮之后能够显示出所回答的问题。
第一步,首先需要解决将答案保存到哪里的问题,很明显,应该将答案保存到Session中,关键是数据结构的设计问题。
(1)这里我们使用HashMap的数据结构来保存所有的答案:Map<String,Map<String,String[]>> allAnswers=new HashMap<String,HashMap<String,String[]>>();
这里key值是pageId,value值是对应页面上的所有答案。
(2)Action中还定义了一个Map<String,String[]>类型的字段,该字段是用于保存当前页中所有请求参数用的,当然也包括所有的答案,该字段和struts2中的params值相同,为此,Action需要实现ParameterAware接口,以方便通过parameterIntercptor拦截器获取到所有参数。
(3)同时为了方便数据处理,还定义了一个“当前的调查(currentSurvey)”字段保存到了Session。
这两个字段的初始化是在进入调查之前完成的,一下的代码中的粗体字段是初始化的过程。
1 public String toSurveyPage() throws Exception{ 2 //重新获取survey对象 3 this.model=this.surveyService.getModelById(this.model.getSurveyId()); 4 float requestPage; 5 //得到请求页,实际上就是orderNo 6 if(parameters.get("requestPage")!=null){ 7 requestPage=Float.parseFloat(parameters.get("requestPage")[0]); 8 }else{ 9 requestPage=this.model.getMinOrderNo(); 10 } 11 Page responsePage=this.surveyService.getResponsePage(this.model,requestPage); 12 ServletActionContext.getContext().put("page",responsePage); 13 14 //将两个参数保存到Session中去 15 this.session.put(this.CURRENT_SURVEY, this.model); 16 this.session.put(ALL_PARAMETERS, new HashMap<String,Map<String,String[]>>()); 17 return "surveyPage"; 18 }
第二步,在单击下一步的时候保存答案到Session中的Map对象。
为了解决这个问题,我们给上一步、下一步、退出、完成按钮进行了特殊的命名,
上一步:submit_pre,下一步:submit_next,退出:submit_exit,完成:submit_done,这样我就能够比较方便的进行判断了。以submit开头是因为这么做比较方便的标记出这四个按钮的一种类型的按钮,方便以后的答案处理。
一旦单击四个按钮中的任何一个按钮Action都会调用一下方法处理:
1 public String doEntrySurvey() throws Exception{ 2 Page oldPage=pageService.getPage(pageId); 3 String submitType=this.getSubmitType(); 4 //上一页 5 if(submitType.endsWith("pre")){ 6 //将答案保存到Session中 7 mergeIntoSession(); 8 Page page=pageService.getPrePage(oldPage); 9 ActionContext.getContext().put("page", page); 10 return "surveyPage"; 11 } 12 //下一页 13 if(submitType.endsWith("next")){ 14 mergeIntoSession(); 15 Page page=pageService.getNextPage(oldPage); 16 ActionContext.getContext().put("page", page); 17 return "surveyPage"; 18 } 19 //完成 20 if(submitType.endsWith("done")){ 21 //首先保存住所有的答案到Session 22 mergeIntoSession(); 23 //然后保存所有的答案到数据库 24 saveAllAnswers(); 25 return "toEntrySurveyPageAction"; 26 } 27 //退出 28 if(submitType.endsWith("exit")){ 29 //首先清除掉session中的所有答案 30 clearAnswersOnSession(); 31 //返回到前端的调查页面,显示出所有可用的调查 32 return "toEntrySurveyPageAction"; 33 } 34 return ""; 35 }
mergeIntoSession方法,该方法是将答案保存到Session的关键方法:
1 //将Parameters中的相关答案选项取出保存到Session中 2 private void mergeIntoSession() { 3 Map<String,Map<String,String[]>>allAnswers=(Map<String, Map<String, String[]>>) this.session.get(this.ALL_PARAMETERS); 4 //将当前页面上的答案集合保存到所有答案的集合中 5 allAnswers.put(pageId+"", this.parameters); //将传递过来的所有参数全部保存起来 6 }
当然代码很简单,这是因为简化处理了,将所有参数都保存了下来,包括非答案的部分。
第三步:回显
对于非文本框的表单,我们使用setTag(pageId,questionId,propertyName)方法来设置属性值,对于文本框类型的表单,我们使用setText(pageId,questionId)方法来设置属性值。
核心代码如下
1 <!-- 定义变量,为当前类型的题型 --> <s:set 2 value="%{#question.questionType}" var="qt"></s:set> <!-- 第一种题型:带有单选框或者复选框的 3 题目标识就是题号小于4,0-3 4 --> <s:if test="#qt lt 4"> 5 <s:iterator value="#question.optionTextArr" status="st"> 6 <input name="q<s:property value='#qid'/>" 7 value='<s:property value="#st.index"/>' 8 type='<s:property value="#qt<2?'radio':'checkbox'"/>' 9 <s:property value="setTag(#pId+'','q'+#qid,#st.index,'checked')"/> 10 > 11 <s:property /> 12 <s:if test="#qt==1 || #qt==3"> 13 <br /> 14 </s:if> 15 </s:iterator> 16 <!-- 处理other的情况 --> 17 <s:if test="#question.other"> 18 <input name="q<s:property value='#qid'/>" 19 value="other" 20 <s:property value="setTag(#pId+'','q'+#qid,'other','checked')"/> 21 type='<s:property value="#qt<2?'radio':'checkbox'"/>'>其它 22 <s:if test="#question.otherType==1"> 23 <input type="text" name='q<s:property value="#qid"/>other' 24 <s:property value="setText(#pId,'q'+#qid+'other')"/> 25 /> 26 </s:if> 27 <s:elseif test="#question.otherType==2"> 28 <select name="q<s:property value='#qid'/>other"> 29 <s:iterator value="#question.otherSelectOptionArr" status="st"> 30 <option 31 <s:property value="setTag(#pId+'','q'+#qid+'other',#st.index,'selected')"/> 32 value='<s:property value="#st.index"/>'> 33 <s:property/> 34 </option> 35 </s:iterator> 36 </select> 37 </s:elseif> 38 </s:if> 39 </s:if> 40 <!-- 第二种题型,是下拉列表类型的题型 --> 41 <s:elseif test="#qt==4"> 42 <select name="q<s:property value='#qid'/>"> 43 <s:iterator value="#question.optionTextArr" status="st"> 44 <option 45 <s:property value="setTag(#pId+'','q'+#qid,#st.index,'selected')"/> 46 value='<s:property value="#st.index"/>'><s:property/></option> 47 </s:iterator> 48 </select> 49 </s:elseif> 50 <s:elseif test="#qt==5"> 51 <input type="text" name="q<s:property value='#qid'/>" 52 <s:property value="setText(#pId,'q'+#qid)"/> 53 /> 54 </s:elseif> <!-- 第三种题型,矩阵问题,6,7,8 --> <s:else> 55 <table style="display: inline-table;"> 56 <!-- 列头 --> 57 <tr> 58 <td></td> 59 <s:iterator value="#question.matrixColTitleArr"> 60 <td><s:property /></td> 61 </s:iterator> 62 </tr> 63 <!-- 输出N多行 --> 64 <s:iterator value="#question.matrixRowTitleArr" 65 status="rowst"> 66 <tr> 67 <td><s:property /></td> 68 <s:iterator value="#question.matrixColTitleArr" 69 status="colst"> 70 <td><s:if test="#qt==6"> 71 <!-- 对于矩阵式单选按钮的问题,必须将每一行视为一个单独的问题 --> 72 <input type="radio" 73 value='<s:property value="#rowst.index+'_'+#colst.index"/>' 74 name="q<s:property value='#qid+"_"+#rowst.index'/>" 75 <s:property value="setTag(#pId+'','q'+#qid+'_'+#rowst.index,#rowst.index+'_'+#colst.index,'checked')"/> 76 > 77 </s:if> <s:elseif test="#qt==7"> 78 <input type="checkbox" 79 value='<s:property value="#rowst.index+'_'+#colst.index"/>' 80 name="q<s:property value='#qid'/>" 81 <s:property value="setTag(#pId+'','q'+#qid,#rowst.index+'_'+#colst.index,'checked')"/> 82 > 83 </s:elseif> <s:elseif test="#qt==8"> 84 <select name="q<s:property value='#qid'/>"> 85 <s:iterator 86 status="selst" 87 value="#question.matrixSelectOptionArr"> 88 <option value='<s:property value="#rowst.index+'_'+#colst.index+'_'+#selst.index"/>' 89 <s:property value="setTag(#pId+'','q'+#qid,#rowst.index+'_'+#colst.index+'_'+#selst.index,'selected')"/> 90 > 91 <s:property /> 92 </option> 93 </s:iterator> 94 </select> 95 </s:elseif></td> 96 </s:iterator> 97 </tr> 98 </s:iterator> 99 </table> 100 </s:else>
Action中定义了setTag方法和setText方法:
setTag方法:
1 public String setTag(String pageId,String name,String value,String tag){ 2 Map<String,Map<String,String[]>>allAnswers=(Map<String, Map<String, String[]>>) this.session.get(this.ALL_PARAMETERS); 3 Map<String,String[]>pageAnswers=allAnswers.get(pageId); 4 if(pageAnswers!=null){ 5 String []values=pageAnswers.get(name); 6 if(values!=null){ 7 for(String temp:values){ 8 if(temp.equals(value)){ 9 return tag; 10 } 11 } 12 } 13 } 14 return ""; 15 }
setText方法:
1 public String setText(String pageId,String name){ 2 Map<String,Map<String,String[]>>allAnswers=(Map<String, Map<String, String[]>>) this.session.get(this.ALL_PARAMETERS); 3 Map<String,String[]>pageAnswers=allAnswers.get(pageId); 4 if(pageAnswers!=null){ 5 String []values=pageAnswers.get(name); 6 if(values!=null){ 7 return "value='"+values[0]+"'"; 8 } 9 } 10 return ""; 11 }
两个方法中特别要注意的是判空操作一定要有,因为第一次访问页面的时候调用setTag方法由于Session中还没有相对应答案实体(pageId对应的答案)所以一定会报出空指针异常,但是被struts2的异常处理机制捕获到而且没有打印,直接就提示“没有找到相关方法”的提示,但是通过debug调试我却发现确实是找到了,实际上这是由于空指针异常导致的方法执行失败导致的,所以一定要判空,虽然不进行判空操作也没有什么问题,但是一次次的提示找不到方法,实在烦人。
到这里,回显功能就已经实现了。
五、处理答案
当单击“提交”的时候,Action会首先调用doEntrySurvey方法保存到所有答案到Session,然后调用saveAllAnswers方法处理所有的答案并保存到数据库,最后重定向到显示所有调查列表的界面。
其核心是saveAllAnswers方法,该方法会过滤所有的答案选项并将答案分门别类的进行整理最后保存到数据库,处理的核心对象是allAnswers(HashMap<String,HashMap<String,String[]>>)。
这里将针对矩阵式单选按钮类型的问题集进行单独处理,因为矩阵式单选按钮类型的问题有一个唯一的标识:以q开头,而且包含'_',所以比较容易单独划分出来。
同时对于非矩阵式单选按钮类型的问题,默认为都带有其他项,这样比较方便处理。
保存答案的方法:
1 private void saveAllAnswers() { 2 /* 3 * 使用一个单独的Map封装所有的单选按钮矩阵题型 4 * Integer类型是questionId 5 * String类型是该题目中的所有单选按钮选项的集合 6 */ 7 Map<Integer,String>matrixRadioMap=new HashMap<Integer,String>(); 8 //使用一个集合保存住所有的答案 9 List<Answer>answers=new ArrayList<Answer>(); 10 Map<String,Map<String,String[]>>allAnswers=(Map<String, Map<String, String[]>>) this.session.get(this.ALL_PARAMETERS); 11 for(Map<String,String[]>map:allAnswers.values()){ 12 String key; 13 String[] values; 14 for(Map.Entry<String, String[]>entry:map.entrySet()){ 15 key=entry.getKey(); 16 values=entry.getValue(); 17 //首先将所有q开头的参数都挑选出来,表明是答案的选项 18 if(key.startsWith("q")){ 19 //这是最普通的一种答案,只是q开头,然后后面跟上一个题目的标号id 20 if(!key.contains("other")&&!key.contains("_")){ 21 Answer answer=new Answer(); 22 answer.setAnswerIndexs(StringUtils.arr2String(values)); //设置所有的答案选项 23 // answer.setAnswerTime(new Date()); //设置答题时间,这个字段先不要填写 24 answer.setQuestionId(getQuestionId(key)); //设置问题id 25 answer.setSurveyId(getSurveyId()); //设置调查id 26 // answer.setUuid(null); //设置回答批次:回答批次不能乱写,一次回答中的所有回答都必须使用一个回答批次 27 //处理其他项,默认所有题目都带有其他项,这样方便处理,注意,这里必须在map变量中查找 28 String[] otherValuesArr=map.get(key+"other"); 29 answer.setOtherAnswer(StringUtils.arr2String(otherValuesArr)); //如果有其它答案的话设置其它答案 30 answers.add(answer); 31 }else if(key.contains("_")){ //如果name属性值中带有"_",表名一定是矩阵式单选按钮的问题 32 Integer questionId=getMatrixRadioQuestionId(key); 33 String oldValue=matrixRadioMap.get(questionId); 34 if(oldValue!=null){ 35 matrixRadioMap.put(questionId, oldValue+","+StringUtils.arr2String(values)); 36 }else{ 37 matrixRadioMap.put(questionId,StringUtils.arr2String(values)); 38 } 39 } 40 } 41 } 42 //最后集中处理单选按钮矩阵式问题,将所有答案保存到anwers中 43 saveRadioMatrixMapToAnwers(answers,matrixRadioMap); 44 } 45 46 /** 47 * 在这里创建SurveyToken对象并绑定到当前线程 48 * TODO 使用分库把保存答案:除了修改配置文件之外,还需要修改该处。 49 */ 50 SurveyToken surveyToken=new SurveyToken(); 51 Survey survey=this.surveyService.getModelById(getSurveyId()); 52 surveyToken.setSurvey(survey); 53 SurveyToken.bind(surveyToken); 54 55 writeAnswersToDB(answers); 56 }
由于矩阵式单选按钮类型的问题需要单独处理,所以另外使用方法将该类问题答案保存到Map(新开的只存放答案的Map,数据结构为Map<Integer,String>,key值为questionId,value值为答案列表)。
1 //将矩阵式单选按钮的问题保存到answes中 2 private void saveRadioMatrixMapToAnwers(List<Answer> answers, Map<Integer, String> matrixRadioMap) { 3 Integer key; 4 String value; 5 for(Map.Entry<Integer, String>entry:matrixRadioMap.entrySet()){ 6 key=entry.getKey(); 7 value=entry.getValue(); 8 Answer answer=new Answer(); 9 answer.setAnswerIndexs(value); 10 // answer.setAnswerTime(new Date()); 11 answer.setQuestionId(key); 12 answer.setSurveyId(getSurveyId()); 13 answers.add(answer); 14 } 15 }
最后集中保存到数据库中
1 /** 2 * 将答案全部写到数据库 3 * @param answers 4 */ 5 private void writeAnswersToDB(List<Answer> answers) { 6 for(Answer answer:answers){ 7 answerService.saveAnswer(answer); 8 } 9 }
至此,已经能够将采集到的答案保存到数据库中了,下一步进行数据统计。