【暑假答辩】Spring+SpringMVC+MyBatis 答辩展示招新网站
- 功能需求
- 页面
- 后台部分细节
- 一、 调用云API(短信服务的JAVA程序+相关类)
- 二、 AJAX+表单验证
- (一)JS实现,AJAX主要是于后台Kaptcha插件生成的验证码交互
- (二)AJAX实现实时成绩修改功能(直接双击成绩栏即可修改成绩)
- 三、验证码配置项及相关代码(基于谷歌Kaptcha插件实现)
- 四、前端部分细节 Echarts实现图表
- 总结
功能需求
- 前端界面简洁美观
- 采集报名信息的表单验证
- 能够查询出笔试的成绩及录取结果
- 能录入招新笔试成绩
- 能够分组导出excel信息表
- 后台报名信息的增删改查
- 图表显示两个组的报名情况(人数,专业,男女比例)
- 调用云短信API统一发送通知短信
页面
后台部分细节
一、 调用云API(短信服务的JAVA程序+相关类)
public class MsgServiceImpl implements MsgService {@Autowiredprivate MsgMapper msgMapper;public void setMsgMapper(MsgMapper msgMapper) {this.msgMapper = msgMapper;}public Msg find(){return msgMapper.findAllMsg();}public void upDateMsg(Msg msg){msgMapper.upDateMsg(msg);}public static void main(String[] args) {String host = "云API地址";String path = "/sms/send";String method = "POST";String appcode = "阿里云code";Map<String, String> headers = new HashMap<String, String>();//最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105headers.put("Authorization", "APPCODE " + appcode);Map<String, String> querys = new HashMap<String, String>();querys.put("receive", "接电话手机号");querys.put("tag", "根据实际模板空白处的短信内容");querys.put("templateId", "模板号");Map<String, String> bodys = new HashMap<String, String>();try {HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);System.out.println(response.toString());} catch (Exception e) {e.printStackTrace();}}
}
public static HttpResponse doGet(String host, String path, String method,Map<String, String> headers,Map<String, String> querys)throws Exception {HttpClient httpClient = wrapClient(host);HttpGet request = new HttpGet(buildUrl(host, path, querys));for (Map.Entry<String, String> e : headers.entrySet()) {request.addHeader(e.getKey(), e.getValue());}return httpClient.execute(request);}public static HttpResponse doPost(String host, String path, String method,Map<String, String> headers,Map<String, String> querys,Map<String, String> bodys)throws Exception {HttpClient httpClient = wrapClient(host);HttpPost request = new HttpPost(buildUrl(host, path, querys));for (Map.Entry<String, String> e : headers.entrySet()) {request.addHeader(e.getKey(), e.getValue());}if (bodys != null) {List<NameValuePair> nameValuePairList = new ArrayList<NameValuePair>();for (String key : bodys.keySet()) {nameValuePairList.add(new BasicNameValuePair(key, bodys.get(key)));}UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, "utf-8");formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8");request.setEntity(formEntity);}return httpClient.execute(request);}public static HttpResponse doPost(String host, String path, String method,Map<String, String> headers,Map<String, String> querys,String body)throws Exception {HttpClient httpClient = wrapClient(host);HttpPost request = new HttpPost(buildUrl(host, path, querys));for (Map.Entry<String, String> e : headers.entrySet()) {request.addHeader(e.getKey(), e.getValue());}if (StringUtils.isNotBlank(body)) {request.setEntity(new StringEntity(body, "utf-8"));}return httpClient.execute(request);}public static HttpResponse doPost(String host, String path, String method,Map<String, String> headers,Map<String, String> querys,byte[] body)throws Exception {HttpClient httpClient = wrapClient(host);HttpPost request = new HttpPost(buildUrl(host, path, querys));for (Map.Entry<String, String> e : headers.entrySet()) {request.addHeader(e.getKey(), e.getValue());}if (body != null) {request.setEntity(new ByteArrayEntity(body));}return httpClient.execute(request);} public static HttpResponse doPut(String host, String path, String method,Map<String, String> headers,Map<String, String> querys,String body)throws Exception {HttpClient httpClient = wrapClient(host);HttpPut request = new HttpPut(buildUrl(host, path, querys));for (Map.Entry<String, String> e : headers.entrySet()) {request.addHeader(e.getKey(), e.getValue());}if (StringUtils.isNotBlank(body)) {request.setEntity(new StringEntity(body, "utf-8"));}return httpClient.execute(request);}public static HttpResponse doPut(String host, String path, String method,Map<String, String> headers,Map<String, String> querys,byte[] body)throws Exception {HttpClient httpClient = wrapClient(host);HttpPut request = new HttpPut(buildUrl(host, path, querys));for (Map.Entry<String, String> e : headers.entrySet()) {request.addHeader(e.getKey(), e.getValue());}if (body != null) {request.setEntity(new ByteArrayEntity(body));}return httpClient.execute(request);}public static HttpResponse doDelete(String host, String path, String method,Map<String, String> headers,Map<String, String> querys)throws Exception {HttpClient httpClient = wrapClient(host);HttpDelete request = new HttpDelete(buildUrl(host, path, querys));for (Map.Entry<String, String> e : headers.entrySet()) {request.addHeader(e.getKey(), e.getValue());}return httpClient.execute(request);}private static String buildUrl(String host, String path, Map<String, String> querys) throws UnsupportedEncodingException {StringBuilder sbUrl = new StringBuilder();sbUrl.append(host);if (!StringUtils.isBlank(path)) {sbUrl.append(path);}if (null != querys) {StringBuilder sbQuery = new StringBuilder();for (Map.Entry<String, String> query : querys.entrySet()) {if (0 < sbQuery.length()) {sbQuery.append("&");}if (StringUtils.isBlank(query.getKey()) && !StringUtils.isBlank(query.getValue())) {sbQuery.append(query.getValue());}if (!StringUtils.isBlank(query.getKey())) {sbQuery.append(query.getKey());if (!StringUtils.isBlank(query.getValue())) {sbQuery.append("=");sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8"));}}}if (0 < sbQuery.length()) {sbUrl.append("?").append(sbQuery);}}return sbUrl.toString();}private static HttpClient wrapClient(String host) {HttpClient httpClient = new DefaultHttpClient();if (host.startsWith("https://")) {sslClient(httpClient);}return httpClient;}private static void sslClient(HttpClient httpClient) {try {SSLContext ctx = SSLContext.getInstance("TLS");X509TrustManager tm = new X509TrustManager() {public X509Certificate[] getAcceptedIssuers() {return null;}public void checkClientTrusted(X509Certificate[] xcs, String str) {}public void checkServerTrusted(X509Certificate[] xcs, String str) {}};ctx.init(null, new TrustManager[] { tm }, null);SSLSocketFactory ssf = new SSLSocketFactory(ctx);ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);ClientConnectionManager ccm = httpClient.getConnectionManager();SchemeRegistry registry = ccm.getSchemeRegistry();registry.register(new Scheme("https", 443, ssf));} catch (KeyManagementException ex) {throw new RuntimeException(ex);} catch (NoSuchAlgorithmException ex) {throw new RuntimeException(ex);}}
}
ps:这段是直接从调用API的公司copy下来的(示例demo)
经过测试可以发送测试短信,但没有合适的账户发送通知短信
二、 AJAX+表单验证
(一)JS实现,AJAX主要是于后台Kaptcha插件生成的验证码交互
var c=c1=c2=c3=c4=c5=c6=c7=c8=false;
function check1(){var name=document.getElementById("name");var wa=document.getElementById("confi1");var na=/^[\u4e00-\u9fa5]{2,8}$/;if(name.value==""){wa.innerText="姓名不能为空";c1=false;}else if(!na.test(name.value)){wa.innerText="这不是一个有效的姓名";c1=false;}else{wa.innerText="";c1=true;}
}function check6(){alert("请检查信息");var name=document.getElementById("username");var wa=document.getElementById("confi6");var na=/^[a-zA-Z0-9_-]{4,16}$/;if(name.value==""){wa.innerText="用户名不能为空";c6=false;}else if(!na.test(name.value)){wa.innerText="4到16位(字母,数字,下划线,减号)";c6=false;}else{var xhr = new XMLHttpRequest()xhr.onreadystatechange=function(){if(xhr.readyState==4&&xhr.status==200){var data= xhr.responseText;if(data=="1"){wa.innerText="用户名可用";c6=true;}else{wa.innerText="用户名不可用";c6=false;}}}//4.发送请求/*var xmlhttp;if (window.XMLHttpRequest){// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码xmlhttp=new XMLHttpRequest();}else{// IE6, IE5 浏览器执行代码xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");}xmlhttp.onreadystatechange=function(){if (xmlhttp.readyState==4 && xmlhttp.status==200){wa.innerText=xmlhttp.responseText;}}xmlhttp.open("GET","${pageContext.request.contextPath}/check",true);xmlhttp.send();wa.innerText="";c6=true;*/var url="register/check?username=";url=url+name.value;xhr.open('POST',url,true);// 使用表单的方式 POST 数据xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");xhr.send("username="+name.value);}alert("请检查信息");}function check2(){var num=document.getElementById("num");var wa=document.getElementById("confi2");var na=/^20([1-2]{1})+(([8-9]{1})|0)+([0-9]{4})+((0[1-9])|([1-9][0-9]))$/;/*01-99 中间四个数字不知道有什么要求没。*/if(num.value==""){wa.innerText="学号不能为空";c2=false;}else if(!na.test(num.value)){wa.innerText="这不是一个有效的学号";c2=false;}else{wa.innerText="";c2=true;}}function check3(){var num=document.getElementById("nu");var wa=document.getElementById("confi3");var na=/^[1-9][0-9]{4,9}$/;if(num.value==""){wa.innerText="QQ不能为空";c3=false;}else if(!na.test(num.value)){wa.innerText="这不是一个有效的QQ";c3=false;}else{wa.innerText="";c3=true;}}function check4(){var num=document.getElementById("phone");var wa=document.getElementById("confi4");var na=/^1([358][0-9]|4[579]|66|9[89])[0-9]{8}$/;if(num.value==""){wa.innerText="号码不能为空";c4=false;}else if(!na.test(num.value)){wa.innerText="这不是一个有效的号码";c4=false;}else{wa.innerText="";c4=true;}}function check5(){var name=document.getElementById("nam");var wa=document.getElementById("confi9");var na=/^[\u4e00-\u9fa5]{2,11}$/;if(name.value==""){wa.innerText="专业不能为空";c5=false;}else if(!na.test(name.value)){wa.innerText="这不是一个有效的专业";c5=false;}else{wa.innerText="";c5=true;}}function check7(){var name=document.getElementById("pass");var name1=document.getElementById("password");var wa=document.getElementById("confi7");if(name.value==""){wa.innerText="请再次填写密码";c7=false;}else if(name.value!=name1.value){wa.innerText="两次密码不一致";c7=false;}else{wa.innerText="";c7=true;}}function check8(){var name=document.getElementById("password");var wa=document.getElementById("confi8");var na=/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,20}$/;var name1=document.getElementById("pass");if(name1.value!=""){check7();}if(name.value==""){wa.innerText="请设置密码";c8=false;}else if(!na.test(name.value)){wa.innerText="密码至少包含 数字和英文,长度6-20";c8=false;}else{wa.innerText="";c8=true;}}function bt(){check6();if(c1&&c2&&c3&&c4&&c5&&c6&&c7&&c8){alert("报名成功");return true;}else{alert("请检查信息");return false;}
}
function checkImg() {var img=document.getElementById("imgObj");img.src=Ctime(img.src);
}
function Ctime(url) {var t=document.getElementById("timestamp");var timestamp = (new Date()).valueOf();url="captcha/getCaptchaImage.do?="+timestamp;t.value=timestamp;return url;
}
function checkCode() {var key=document.getElementById("code");var test=document.getElementById("timestamp");var wa=document.getElementById("waring");var xhr = new XMLHttpRequest();xhr.onreadystatechange=function(){if(xhr.readyState==4&&xhr.status==200){var data= xhr.responseText;if(data=="1"){wa.innerText="验证成功";c=true;}else{wa.innerText="验证失败,请重新输入验证码";checkImg();c=false;}}}var url="captcha/checkCaptcha.do?timestamp="+test.value+"&code="+key.value;xhr.open('POST',url,true);// 使用表单的方式 POST 数据xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");xhr.send("timestamp="+test.value+"&code="+key.value);}
(二)AJAX实现实时成绩修改功能(直接双击成绩栏即可修改成绩)
function ChangeTest(key) {var test=document.getElementById(key);var wa=document.getElementById(key+"!");var xhr = new XMLHttpRequest();xhr.onreadystatechange=function(){if(xhr.readyState==4&&xhr.status==200){var data= xhr.responseText;if(data=="1"){wa.innerText="修改成功";c6=true;}else{wa.innerText="修改失败";c6=false;}}}var url="ChangeTest?id=";url=url+key+"&test=";url=url+test.value;xhr.open('POST',url,true);// 使用表单的方式 POST 数据xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");xhr.send("id="+key+"&test="+test.value);}
三、验证码配置项及相关代码(基于谷歌Kaptcha插件实现)
Spring-service.xml
<bean id="captchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha"><property name="config"><bean class="com.google.code.kaptcha.util.Config"><constructor-arg><props><prop key="kaptcha.border">no</prop><prop key="kaptcha.border.color">105,179,90</prop><prop key="kaptcha.textproducer.font.color">red</prop><prop key="kaptcha.image.width">100</prop><prop key="kaptcha.textproducer.font.size">30</prop><prop key="kaptcha.image.height">40</prop><prop key="kaptcha.session.key">code</prop><prop key="kaptcha.textproducer.char.length">4</prop><prop key="kaptcha.textproducer.font.names">宋体,楷体,微软雅黑</prop></props></constructor-arg></bean></property></bean>
<servlet><servlet-name>Kaptcha</servlet-name><servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class><!-- 是否有边框 --><init-param><param-name>kaptcha.border</param-name><param-value>no</param-value></init-param><!-- 字体颜色 --><init-param><param-name>kaptcha.textproducer.font.color</param-name><param-value>red</param-value></init-param><!-- 图片宽度 --><init-param><param-name>kaptcha.image.width</param-name><param-value>135</param-value></init-param><!-- 使用哪些字符生成验证码 --><init-param><param-name>kaptcha.textproducer.char.string</param-name><param-value>ACDEFHKPRSTWX345679</param-value></init-param><!-- 图片高度 --><init-param><param-name>kaptcha.image.height</param-name><param-value>50</param-value></init-param><!-- 字体大小 --><init-param><param-name>kaptcha.textproducer.font.size</param-name><param-value>43</param-value></init-param><!-- 干扰线的颜色 --><init-param><param-name>kaptcha.noise.color</param-name><param-value>black</param-value></init-param><!-- 字符个数 --><init-param><param-name>kaptcha.textproducer.char.length</param-name><param-value>4</param-value></init-param><!-- 字体 --><init-param><param-name>kaptcha.textproducer.font.names</param-name><param-value>Arial</param-value></init-param></servlet><servlet-mapping><servlet-name>Kaptcha</servlet-name><url-pattern>/Kaptcha</url-pattern></servlet-mapping><servlet><servlet-name>springmvc</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet>
@Controller
@RequestMapping("/")
public class CaptchaImageCreateController {private Producer captchaProducer = null;@Autowiredpublic void setCaptchaProducer(Producer captchaProducer) {this.captchaProducer = captchaProducer;}@RequestMapping("/captcha-image")public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {response.setDateHeader("Expires", 0);// Set standard HTTP/1.1 no-cache headers.response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");// Set IE extended HTTP/1.1 no-cache headers (use addHeader).response.addHeader("Cache-Control", "post-check=0, pre-check=0");// Set standard HTTP/1.0 no-cache header.response.setHeader("Pragma", "no-cache");// return a jpegresponse.setContentType("image/jpeg");// create the text for the imageString capText = captchaProducer.createText();// store the text in the sessionrequest.getSession().setAttribute(Constants.KAPTCHA_SESSION_KEY, capText);// create the image with the textBufferedImage bi = captchaProducer.createImage(capText);ServletOutputStream out = response.getOutputStream();// write the data outImageIO.write(bi, "jpg", out);try {out.flush();} finally {out.close();}return null;}}
timestamp是指时间戳,避免因为图片缓存而引起后台验证码与前端图片不符
@Controller
@RequestMapping(value = "/captcha")
public class CaptchaController {private static final Log log = LogFactory.getLog(CaptchaController.class);@Autowiredprivate Producer captchaProducer;@RequestMapping(value = "/getCaptcha.do", method = RequestMethod.GET)public String getCaptcha(Model model) {model.addAttribute("timestamp", System.currentTimeMillis());return "captcha";}@RequestMapping(value = "/getCaptchaImage.do", method = RequestMethod.GET)public ModelAndView getCaptchaImage(Model model,HttpServletRequest request, HttpServletResponse response,@RequestParam(value = "timestamp", required = false) String timestamp) throws IOException {if (StringUtils.isEmpty(timestamp)) {model.addAttribute("timestamp", System.currentTimeMillis());} else {model.addAttribute("timestamp", timestamp);}System.out.println("!!");response.setDateHeader("Expires", 0);response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");response.addHeader("Cache-Control", "post-check=0, pre-check=0");response.setHeader("Pragma", "no-cache");response.setContentType("image/jpeg");String capText = captchaProducer.createText();request.getSession().setAttribute(Constants.KAPTCHA_SESSION_KEY, capText);System.out.println(capText);BufferedImage bi = captchaProducer.createImage(capText);ServletOutputStream out = response.getOutputStream();ImageIO.write(bi, "jpg", out);try {out.flush();} finally {out.close();}return null;}@RequestMapping(value = "/checkCaptcha.do")@ResponseBodypublic void checkCaptcha(@RequestParam(value = "timestamp", required = false) String timestamp, @RequestParam(value = "code", required = false) String code,HttpServletRequest request ,HttpServletResponse response) throws IOException {boolean returnStr = false;String original =(String) request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);code=request.getParameter("code");System.out.println("!"+timestamp);System.out.println(code+"@");System.out.println(original+"!");String data="0";if (code.equals(original)) {data="1";}elsedata="0";System.out.println(data);response.getWriter().write(data);}
}
四、前端部分细节 Echarts实现图表
<script type="text/javascript ">var myChart = echarts.init(document.getElementById('pid-div'));option = {title: {text: '智能组各专业报名人数统计表',left: 'center',textStyle: {fontSize: 25}},tooltip: {trigger: 'item',formatter: '{a} <br/>{b} : {c} ({d}%)',textStyle: {fontSize: 15}},legend: {textStyle: {fontSize: 15},type: 'scroll',orient: 'vertical',right: 75,top: 250,bottom: 20,data: this.legend,},series: [{label: {textStyle: {fontSize: 15}},name: '专业',type: 'pie',radius: '55%',center: ['40%', '50%'],data: [{name: "数字媒体技术",value: "10"}, {name: "计算机科学与技术",value: "50"}, {name: "物联网工程",value: "10"}, {name: "电子信息科学与技术",value: "40"}, {name: "通信工程",value: "30"}, {name: "电子信息工程",value: "10"}, {name: "其他",value: "40"}],emphasis: {itemStyle: {shadowBlur: 10,shadowOffsetX: 0,shadowColor: 'rgba(0, 0, 0, 0.5)'}}}]};myChart.setOption(option);myChart.showLoading();myChart.hideLoading(); // 隐藏加载动画$.ajax({type:"POST",url:'${pageContext.request.contextPath}/manage/queryForListIntelMajor',contentType:"application/json;charset=utf-8",success:function (result,status) {var content=JSON.parse(JSON.stringify(result));if(content.name==200){myChart.setOption({series: [{data: [{name: "数字媒体技术",value: content.number[0]},{name: "物联网工程",value: content.number[1]},{name: "计算机科学与技术",value: content.number[2]},{name: "电子信息科学与技术",value: content.number[3]},{name: "通信工程",value: content.number[4]},{name: "电子信息工程",value: content.number[5]},{name: "其他",value: content.number[6]},],}]})}}})
</script>
总结
1.前端页面还有比较大的改动空间,报错不够美观,后续还会更新
2.暂未部署到服务器上(业务不熟练)
3.学习到了搭建网站的流程,了解了工厂模式的实现方法
4.学习到了搭建网站N多插件的使用方法