一、JQuery获取form表单数据,用以ajax请求传输
1、逐一获取标签数据,然后在ajax请求的data中拼接
<script>
$(document).ready(function() {
$("#regionBtn").click(function () {
var url0=$("#form1").attr("action");//获取请求后端servlet的名字
var username0=$("#username").val();
var password0=$("#password").val();
alert(username0+","+password0);
$.ajax({
type:"post",
url:url0,
cache:false,
data:{"username0":username0 , "password0":password0},
dataType:"json", //是后端传回来的数据类型,不是前端传过去的数据类型
success:function(re)
{
alert("ok");
},
error: function(re)
{
alert("no");
}
})
})
})
</script>
问题来了:当form表单数据很多时,这样一个一个的取和传非常的繁琐复杂,这时就需要用序列化的方式获取参数来解决上述问题了
2、(当form表单只有文本数据时)使用serialize()接收表单数据
用户注册<br>
<form action="regionServlet" method="POST" id="form1" >
用户名:<input type="text" name="username" id="username"><br>
密码:<input type="password" name="password" id="password"><br>
</form>
<button id="regionBtn" >注册</button>
var data0=$("#form1").serialize();
使用serialize()序列化方法,可以把表单中的所有数据取出来组成一个串。序列化后的形式如图所示:
这个串可以之间作为ajax的data参数值,将入参传至后端servlet
<script>
$(document).ready(function() {
$("#regionBtn").click(function () {
var url0=$("#form1").attr("action");
var data0=$("#form1").serialize();
alert(data0);
$.ajax({
type:"post",
url:url0,
cache:false,
data:data0,
dataType:"json",
success:function(re)
{
alert("ok");
},
error: function(re)
{
alert("no");
}
})
})
})
</script>
注意:使用serialize()时,提交按钮要放在form表单的外面。
serialize()方法可以方便的接收form表单中所有非文件参数,但是当表单中有文件参数时该怎么做呢?
3、当form表单中包含文件数据时,使用FormData接收表单数据
1)
用户注册<br>
<form action="regionServlet" method="POST" id="form1" enctype="multipart/form-data">
用户名:<input type="text" name="username" id="username"><br>
密码:<input type="password" name="password" id="password"><br>
头像:<input type="file" name="tx" id="tx"><br>
</form>
<button id="regionBtn" >注册</button>
FormData会将表单数据以键值对的形式来表示,并且还可以通过key来追加、修改、获取等操作。
var data0=new FormData($("#form2")[0]);
通过上述方法,data0就获取了form表单的用户名、密码两个文本参数,以及头像这个文件参数;之后将data0放在ajax请求的data后即可。
<script>
$(document).ready(function() {
$("#regionBtn").click(function () {
var url0=$("#form1").attr("action");//获取请求后端servlet的名字
var data0=new FormData($("#form1")[0]);
$.ajax({
type:"post",
url:url0,
cache:false,
data:data0,
processData:false,//需设置为false。因为data值是FormData对象,不需要对数据做处理
contentType:false,//需设置为false。因为是FormData对象,且已经声明了属性enctype="multipart/form-data"
dataType:"json", //是后端传回来的数据类型,不是前端传过去的数据类型
success:function(re)
{
alert("ok");
},
error: function(re)
{
alert("no");
}
})
})
})
</script>
2)需要注意,当入参中有文本参数时,ajax请求需要添加参数
processData:false,//需设置为false。因为data值是FormData对象,不需要对数据做处理
contentType:false,//需设置为false。因为是FormData对象,且已经声明了属性enctype="multipart/form-data"
4、后端接收文件参数
0)注意:接收文件参数,一般只能用post请求、不能用get请求,因为get请求有大小限制。
1)只有一个文件参数时,可以用MultipartFile作形参接收(需要改名字,可以用@RequestParam注解),如下
@PostMapping(value = "/uuApplyUserInfo")
public AjaxResult uuApplyUserInfo(@RequestParam(value = "newFileName",required = false) MultipartFile file) {
......
}
2)如果是多个参数时,我一般是用实体类接收,实体类中的属性包含全部入参,用MultipartFile接收文件参数,如下
@PostMapping("/pushMsg")
@ResponseBody
public Result pushMsg(PushMessage pushMassage){
......
}
PushMessage类如下
二、idea热部署+spring boot项目修改jsp后需要重启项目的问题
1、idea热部署
对于一个普通的ssm+tomcat项目,测试时配置tomcat,一般都会配置热部署,如下图
第一个是更新时做的操作,即刷新页面时做什么;这个一般选择 update classes and resources ---- 更新java,jsp和静态资源;
第二个是指当idea失去焦点时,做什么。
所以这里最优解应该为
因为On frame deactivation选项是在IDE失去焦点的情况下 自动触发,而开发过程中 可能需要查询资料 或 与人聊天 或干其它事,IDE会不停的失去焦点。每次失去焦点就自动触发 update ,造成CPU不必要的浪费,使电脑变慢,所以没有必要这样,设置为Do nothing 最好,官方也默认的是 Do nothing。
2、springboot项目修改jsp后需要重启项目才能更新页面
1、对于这个问题,网上给出以下两种解决方案:
1)在配置文件中加入以下配置:
properties文件
#1.5版本
server.jsp-servlet.init-parameters.development=true
#2.0以上版本
server.servlet.jsp.init-parameters.development=true
yml文件
#2.0以上版本
server:
servlet:
jsp:
init-parameters:
development: true
2)网上说,还有一种方法是通过加入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
就解决问题了;据说该方法,还可以通过配置文件,控制刷新时更新哪些包下的文件、不更新哪些包下的文件
#添加那个目录的文件需要restart
spring.devtools.restart.additional-paths=src/main/java
#排除那个目录的文件不需要restart
spring.devtools.restart.exclude=static/**,public/**
【实践】以上两种方法,实测都没有效果;各自单独测试、两个组合测试都不行。不知道是版本更迭的原因,还是我的情况比较特殊,还是他们胡说。
2、真正有用的解决方式
1)配置idea
开启自动编译及automake功能
按住 ctrl+alt+shift+/
2)配置On Update action为---- Hot swap classes and update trigger file if failed
通过以上配置,就可以实现热部署了,对于页面的修改不用重启就能看到效果。
三、用正则表达式限制输入内容
1、通过给文本框绑定事件,写函数来限制输入内容。
这种方法适合做比较复杂的限定;也可以使标签看起来简洁一些。
1)限制输入框只能输数字、两位小数
<label>单位存储量:</label>
<div class="register_text">
<input id="unitSave" name="unitSave" type="text" onkeyup="clearNoNum(this)" autocomplete="off" class="register_input width-200"/> ml/份
</div>
function clearNoNum(obj){
obj.value = obj.value.replace(/[^\d.]/g,""); //清除"数字"和"."以外的字符
obj.value = obj.value.replace(/^\./g,""); //验证第一个字符是数字
obj.value = obj.value.replace(/\.{2,}/g,"."); //只保留第一个, 清除多余的
obj.value = obj.value.replace(".","$#$").replace(/\./g,"").replace("$#$",".");
obj.value = obj.value.replace(/^(\-)*(\d+)\.(\d\d).*$/,'$1$2.$3'); //只能输入两个小数
if(obj.value.indexOf(".")< 0 && obj.value !=""){//以上已经过滤,此处控制的是如果没有小数点,首位不能为类似于 01、02的金额
if(obj.value.substr(0,1) == '0' && obj.value.length == 2){
obj.value= parseFloat(obj.value);
}
}
}
2)限制输入框只能输整数
function clearIsnotNumSaveInt(obj){
obj.value = obj.value.replace(/[^\d]/g,""); //清除"数字"以外的字符
obj.value = obj.value.replace(/^\./g,""); //验证第一个字符是数字
obj.value = obj.value.replace(/\.{2,}/g,"."); //只保留第一个, 清除多余的
}
3)限制手机号(位数、只能为数字等)
<th>联系电话</th>
<td><input type="text" name="principal.telephone" value="${defaultPrincipal.telephone}" autocomplete="off" onkeyup="checkInputTelephone(this)"/></td>
//校验11位手机号
function checkInputTelephone(obj) {
obj.value = obj.value.replace(/\D+/g,'');
if (obj.value.length >=11) {
obj.value = obj.value.substr(0,11);
var myreg = /^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1}))+\d{8})$/g;
if(!myreg.test(obj.value)) {
obj.value = '请输入正确的手机号';
}
}
}
2、通过给文本框添加属性,进而限制输入内容。
1)限制输入内容只能为中文或者英文字符
<input style="display: inline-block; width: 300px; border: 1px solid #ccc"
name="personName" id="personName"
type="text"
onkeyup="value=value.replace(/[^\a-\z\A-\Z\u4E00-\u9FA5]/g,'')"
onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\a-\z\A-\Z\u4E00-\u9FA5]/g,''))"
maxlength="10"
autocomplete="off"
class="register_input" />
其中onkeyup和onbeforepaste限制输入内容只能为中文和英文字符,
maxlength限制输入最大长度为10;
autocomplete是关闭浏览器的自动补全(缓存)
2)限制只能汉字
<th>姓名</th>
<td>
<input type="text" name="principal.personName" value="${defaultPrincipal.personName}" autocomplete="off"
onkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,'')"
onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\u4E00-\u9FA5]/g,''))"
maxlength="5"/>
</td>
3、其他格式限制
JS 控制文本框只能输入数字
<input onkeyup="value=value.replace(/[^0-9]/g,'')"onpaste="value=value.replace(/[^0-9]/g,'')" oncontextmenu ="value=value.replace(/[^0-9]/g,'')">
JS 控制文本框只能输入数字、小数点
<inputonkeyup="value=value.replace(/[^\0-9.]/g,'')"onpaste="value=value.replace(/[^\0-9.]/g,'')" oncontextmenu ="value=value.replace(/[^\0-9.]/g,'')">
JS 控制文本框只能输入英文
<inputonkeyup="value=value.replace(/[^\a-\z\A-\Z]/g,'')"onpaste="value=value.replace(/[^\a-\z\A-\Z]/g,'')" oncontextmenu ="value=value.replace(/[^\a-\z\A-\Z]/g,'')">
JS 控制文本框只能输入英文、数字
<inputonkeyup="value=value.replace(/[^\a-\z\A-\Z0-9]/g,'')"onpaste="value=value.replace(/[^\a-\z\A-\Z0-9]/g,'')" oncontextmenu="value=value.replace(/[^\a-\z\A-\Z0-9]/g,'')">
JS 控制文本框只能输入中文
<inputonkeyup="value=value.replace(/[^\u4E00-\u9FA5]/g,'')"onpaste="value=value.replace(/[^\u4E00-\u9FA5]/g,'')" oncontextmenu="value=value.replace(/[^\u4E00-\u9FA5]/g,'')">
JS 控制文本框只能输入中文、英文、数字
<inputonkeyup="value=value.replace(/[^\a-\z\A-\Z0-9\u4E00-\u9FA5]/g,'')"onpaste="value=value.replace(/[^\a-\z\A-\Z0-9\u4E00-\u9FA5]/g,'')"oncontextmenu ="value=value.replace(/[^\a-\z\A-\Z0-9\u4E00-\u9FA5]/g,'')">
JS 控制文本框只能输入中文、英文、数字、空格
<inputonkeyup="value=value.replace(/[^\a-\z\A-\Z0-9\u4E00-\u9FA5]/g,'')"onpaste="value=value.replace(/[^\a-\z\A-\Z0-9\u4E00-\u9FA5]/g,'')" oncontextmenu ="value=value.replace(/[^\a-\z\A-\Z0-9\u4E00-\u9FA5]/g,'')">
JS 控制文本框只能输入中文、英文、数字、小数点
<inputonkeyup="value=value.replace(/[^\a-\z\A-\Z0-9\u4E00-\u9FA5\.]/g,'')"onpaste="value=value.replace(/[^\a-\z\A-\Z0-9\u4E00-\u9FA5\.]/g,'')"oncontextmenu ="value=value.replace(/[^\a-\z\A-\Z0-9\u4E00-\u9FA5\.]/g,'')">
总结:
先在’里输入
onkeyup="value=value.replace(/[^\X]/g,'')"
然后在(/[\X]/g,‘’)里的 X换成你想输入的代码就可以了,
中文u4E00-u9FA5,数字0-9,英文a-z\A-Z,其它符号@、点或其它符号。
也可以多个,用\隔开就行了。
例如:中英文 + 数字 + @符号 + 点符号 \a-\z\A-\Z0-9\u4E00-\u9FA5@.
若想在文本框里不能右键弹出菜单和不能粘贴进复制的信息的话
就要在’'里输入οnpaste=“return false” οncοntextmenu=“return false;”
四、自动补全
1、使用场景:
在做微生物系统的时候,有些填报需要用户填写他们实验室研究的是哪种病原微生物;这些微生物的名称、危害等级、英文名等都是固定的,不能瞎填(可以理解为字典值);不仅后台要验证正确性,前端也要有异步的自动补全功能,例如“新型冠状病毒”,当用户输入“新”时,就要展示全部的相关选项,用户直接选择就可以填报想要的、正确的、准确的结果,页面效果如下
2、实现方式
实现方式应该有很多种,有些可能还可以做成自动填写很多个字段的效果;但是我这里只记录一种,使用bootstrap-typehead自动补全插件的方法;一是因为简单,非常容易实现;二是对于一个主要做后端的开发,typehead提供的自动补全功能就够用了,其他的多数可以用后端方法弥补。
1)首先要添加bootstrap-typeahead插件
先在系统文件夹下添加插件
然后在jsp页面引入插件
<script src="${ctx}/res/js/typeahead/bootstrap3-typeahead.min.js"></script>
2)为了不让浏览器的自动补全功能影响我们的显示效果,先关掉文本框浏览器的自动补全
<li >
<label>病原微生物名称:</label>
<div class="register_text">
<input id="microbeName" name="microbeName" type="text" class="register_input width-200" placeholder="关键字搜索" autocomplete="off"/>
</div>
</li>
3)调用typehead插件提供的typehead()方法
//微生物名称自动补全
$("#microbeName").typeahead({
source:function(query, process){
$.get(
ctx + "/microbe/findMicNameList",
{"subName": query},
function (data) {
process(data);
},
"json"
);
},
delay: 500
})
这个方法基本上就是一个ajax请求,但是对于返回值自动做了处理,为了得到规定格式的返回结果,typehead方法对请求方式、返回结果做了限定。
其中function的第一个参数query是文本框输入的内容,第二个参数process是对结果处理、得到自动补全显示效果的方法;query用于调用后端查询接口时作为参数传给后端,process()中放返回的结果。
我们只需要编写查询接口,返回指定数据,剩下的展示,typeahead插件会帮我们处理。
后端接口,返回List
五、用sessionStorage解决跳转页面再返回,不能回到之前分页、而是返回到首页的问题
1、场景
在列表页、(分页为)第3页,跳转查看页面,点取消后,按道理应该回到我点查看前的页面也就是第3页;但是不做处理刷新的话,就回到首页了。
2、问题解决思路
在跳转查看页前,将当前页码、查询条件(如果有的话)等,存入sessionStorage;在查看页点取消后、重新加载列表页前,从sessionStorage取出pageNum等,作为请求参数放入查询中,这样就可以“返回”点查看时的页面了。
3、实例一:
1)在跳转查看页前,把当前言相关参数存入session,将来要重新回到当前页需要哪些参数,这里就往session中放哪些参数,核心语句是
window.sessionStorage.setItem(“pageNum”, pageNum);
//跳转查看页面方法
function toCheckMicRecord(recordId) {
var pageNum = $("#pageNum").val();
window.sessionStorage.setItem("pageNum", pageNum);
window.sessionStorage.setItem("monthMicRecordMark", "3");
var url = "/micMicrobeRecord2/toCheckMicRecord?recordId=" + recordId;
myMenu(url);
}
2)
//返回
$(".close").click(function () {
var pageNum = window.sessionStorage.getItem("pageNum");
var mark = window.sessionStorage.getItem("monthMicRecordMark");
if(typeof(mark)=="undefined" || mark=="3"){
loadMonthMicRecordCheckPage(pageNum);
}else if(mark=="2"){
loadMonthMicRecordCheckPageArea();
}else if(mark=="1"){
loadMonthMicRecordCheckPageCity();
}
})
//返回机构、实验室列表
function loadMonthMicRecordCheckPage(pageNum) {
$.ajax({
url: ctx+"/micMicrobeRecord2/toListPage",
type: 'POST',
data: {
"pageNum": pageNum
},
async: false,
success: function (result) {
if (result != null) {
window.sessionStorage.removeItem("pageNum");
$(".main_right").empty();
$(".main_right").html(result);// 要刷新的div
}else {
alert("ajax返回result为null");
}
},
error : function() {
alert("请求失败,网络错误,请稍后再试!");
}
});
}
4、实例二:
1)从列表页跳转详情页时,保存查询条件、当前页码,放入session中;
核心代码是
var data = $(“form”).serialize();
以及
window.sessionStorage.setItem(“officeApprovalData”, data);
//跳转准运证
function toTransportPaper(approvalId) {
var data = $("form").serialize();
window.sessionStorage.setItem("officeApprovalData", data);
var url = "/officeApproval/toApprovalPaper?approvalId="+approvalId+"&paperMark=2";
myMenu(url);
}
2)从详情页点返回按钮,实际是重新查询列表页,但是查询条件和页码要用跳转详情页前的数据。
最后,session中的数据用完后最好清除。
//返回
$(".close").click(function () {
loadOfficeApprovalList();
})
//返回行政审批列表页
function loadOfficeApprovalList() {
var data = window.sessionStorage.getItem("officeApprovalData");
var url = ctx+"/officeApproval/toOfficeApproval";
$.ajax({
type : "post",
url : url,
data: data,
success : function(data) {
//清数据
window.sessionStorage.removeItem("pageNum");
window.sessionStorage.removeItem("officeApprovalData");
$(".right_box").empty();
$(".right_box").html(data);// 要刷新的div
},
error : function() {
alert("请求失败,网络错误,请稍后再试!");
}
});
}
六、页面按指定格式展示时间
1、补充前提:JSTL 核心标签库标签共有13个,功能上分为4类:
1)表达式控制标签:out、set、remove、catch
2)流程控制标签:if、choose、when、otherwise
3)循环标签:forEach、forTokens
4)URL操作标签:import、url、redirect
使用标签时,一定要在jsp文件头加入以下代码:
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
使用fmt 对时间进行格式化的时候需要引入如下
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
2、具体应用:使用标签,将时间按指定格式展示;注意,使用要求数据类型为Date,如果是TimeStamp需要转换格式(我自己测好像是这样的)。
示例:
<fmt:formatDate value="${p.destructionTime}" pattern="yyyy-MM-dd"/> 结果:2017-08-12
<fmt:formatDate value="${XXXX}" type="both"/> 结果:2017-08-12 17:28:26
<fmt:formatDate value="${XXXX}" type="date"/> 结果:2017-08-12
<fmt:formatDate value="${XXXX}" type="time"/> 结果:21:20:12
<fmt:formatDate value="${XXXX}" type="date" dateStyle="default"/> 结果:2017-5-31
<fmt:formatDate value="${XXXX}" type="date" dateStyle="short"/> 结果:07-5-31
<fmt:formatDate value="${XXXX}" type="date" dateStyle="medium"/> 结果:2017-5-31
<fmt:formatDate value="${XXXX}" type="date" dateStyle="long"/> 结果:2017年5月31日
<fmt:formatDate value="${XXXX}" type="date" dateStyle="full"/> 结果:2017年8月12日 星期六
<fmt:formatDate value="${XXXX}" type="time" timeStyle="default"/> 结果:23:59:59
<fmt:formatDate value="${XXXX}" type="time" timeStyle="short"/> 结果:下午11:59
<fmt:formatDate value="${XXXX}" type="time" timeStyle="medium"/> 结果:23:59:59
<fmt:formatDate value="${isoDate}" type="time" timeStyle="long"/> 结果:下午11时59分59秒
<fmt:formatDate value="${XXXX}" type="time" timeStyle="full"/> 结果:下午11时59分59秒 CDT
<fmt:formatDate value="${date}" type="both" pattern="EEEE, MMMM d, yyyy HH:mm:ss Z"/> 结果:星期四, 四月 1, 2017 13:30:00 -0600
<fmt:formatDate value="${isoDate}" type="both" pattern="d MMM yy, h:m:s a zzzz/>结果:31 五月 04, 11:59:59 下午 中央夏令时
七、返回上一个页面的方法(非脚本返回)
1、 <a href="javascript:history.back(-1)">返回上一页</a>
2、<a href="javascript:;" onClick="javascript:history.back(-1);">返回上一页</a>
3、用图片做
<a href="javascript :;" onClick="javascript :history.back(-1);"><img src="图片路径" border="0" title="返回上一页"></a>
4、用按钮做
<input type="button" name="Submit" οnclick="javascript:history.back(-1);" value="返回上一页">
5、用js实现页面自动返回到上一页
几秒钟后自动返回上一页代码:(加入两个head间,3000表示3秒)
<script type="text/javascript">setTimeout("history.go(-1)", 3000); </script>
<SCRIPT language=javascript>
function go()
{undefined
window.history.go(-1);
}
setTimeout("go()",3000);
</SCRIPT>
6、向上一页, 返回两个页面: history.go(-2);
页面跳转:οnclick=“window.location.href=‘list.php’”
八、配合浏览器修改jsp页面的div样式
1、场景描述
写了一个jsp页面,对其中一个模块的页面样式不满意;接下来介绍的方法,可以通过浏览器调整,然后把调整后的、满意的样式复制到后台。
另外,调样式方法很多;此方法很简单,适用于我这样的后台开发。
2、第一步
浏览器f12,用element的select工具定位到我们要调样式的模块
3、第二步
在左侧的computed下,调整模块的样式(这里的调整不会改变代码,刷新页面就复原了);能调整模块大小、在整个页面的位置等,其他的可在style下改。下面截图中的就代表了我们选中的模块在页面的一些参数,红框框住的地方都可以修改,浏览器会同步调整页面样式,我们可以看到修改后的样式,非常直观。
4、第三步
样式改的满意后,我们通过修改后的元素(截图中的按钮),进入style中对应的style代码;把这段代码复制上。
5、给我们要改样式的div起一个id,然后在style标签中按下图中的格式,把从浏览器上复制下的代码粘贴在这里,页面就变成我们想要的样式了!是不是非常简单、高效?