先看数据库的代码:
-- 创建数据库
create database musicdb
use musicdb
-- 创建表
-- 用户表
create table [user](
uid int primary key identity(1,1),
name varchar(20) not null,
pwd varchar(20) not null,
[desc] varchar(50)
)
create table music(
mid int primary key identity(101,1),
musicName varchar(50) not null,
singer varchar(20) not null, --歌手
album varchar(20) not null, --专辑
timer varchar(20), --时长
position varchar(100), --位置
)
select * from music
select * from [user]
然后vs2019 创建AspNet Web项目,添加Default.aspx
有一定基础的同学,应该知道,AspNet 分两部分,一部分是前台界面,另一部分是后台代码,Aspnet使用了CodeBehind 代码后置的技术
Default.aspx 前台设计界面:
<div class="row">
<h3 class="text-center" style="color: orange">音乐库 管理</h3>
</div>
<div class="row">
<asp:GridView ID="GridView1" runat="server" CssClass="table table-hover table-striped" AutoGenerateColumns="False" OnRowCommand="GridView1_RowCommand" OnRowDeleting="GridView1_RowDeleting" OnRowEditing="GridView1_RowEditing" DataKeyNames="mid" OnRowUpdating="GridView1_RowUpdating" OnRowCancelingEdit="GridView1_RowCancelingEdit">
<Columns>
<asp:BoundField DataField="mid" HeaderText="序号" />
<asp:BoundField DataField="musicName" HeaderText="歌曲名" />
<asp:BoundField DataField="singer" HeaderText="歌手" />
<asp:BoundField DataField="album" HeaderText="专辑" />
<asp:BoundField DataField="timer" HeaderText="时长" />
<asp:BoundField DataField="position" HeaderText="存储位置" />
<asp:TemplateField HeaderText="操作" ShowHeader="False">
<EditItemTemplate>
<asp:LinkButton ID="LinkButton1" runat="server" CausesValidation="True" CommandName="Update" Text="更新"></asp:LinkButton>
<asp:LinkButton ID="LinkButton2" runat="server" CausesValidation="False" CommandName="Cancel" Text="取消"></asp:LinkButton>
</EditItemTemplate>
<ItemTemplate>
<asp:LinkButton ID="LinkButton3" runat="server" CausesValidation="False" CommandName="Edit" Text="修改"></asp:LinkButton>
<asp:LinkButton ID="LinkButton1" runat="server" CausesValidation="False" CommandName="Delete" Text="删除"></asp:LinkButton>
<a href="/add.aspx">插入</a>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
Default.aspx.cs 后台代码
public partial class _Default : Page
{
public string name = "";
protected void Page_Load(object sender, EventArgs e) // 首次加载
{
if (!IsPostBack) {
if (Session["userName"]==null)
{
Response.Redirect("~/login.aspx");
}
else
{
name = Session["userName"].ToString();
LoadMusic();
}
}
}
protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
string id = GridView1.Rows[e.RowIndex].Cells[0].Text;
string sql = $"delete from music where mid='{id}'";
if (DBHelper.Update(sql))
{
LoadMusic();
}
else {
Response.Write("<script>alert('删除失败!')</script>");
}
}
protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
//string mid = e.CommandArgument.ToString();
name = Session["userName"].ToString();
GridView1.EditIndex = e.NewEditIndex;
LoadMusic();
}
private void LoadMusic()
{
this.GridView1.DataSource = DBHelper.Select("select * from music");
this.GridView1.DataBind();
}
protected void GridView1_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
string id = this.GridView1.DataKeys[e.RowIndex].Value.ToString();
string name = ((TextBox)(GridView1.Rows[e.RowIndex].Cells[1].Controls[0])).Text;
string signer= ((TextBox)(GridView1.Rows[e.RowIndex].Cells[2].Controls[0])).Text;
string album= ((TextBox)(GridView1.Rows[e.RowIndex].Cells[3].Controls[0])).Text;
string timer= ((TextBox)(GridView1.Rows[e.RowIndex].Cells[4].Controls[0])).Text;
string p= ((TextBox)(GridView1.Rows[e.RowIndex].Cells[5].Controls[0])).Text;
string sql = $"update music set musicName='{name}',singer='{signer}',album='{album}',timer='{timer}',position='{p}' where mid='{id}'";
if (DBHelper.Update(sql)) {
Response.Write("<script>alert('修改成功!')</script>");
LoadMusic();
}
}
protected void GridView1_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
{
name = Session["userName"].ToString();
GridView1.EditIndex = -1;
LoadMusic();
}
}
效果图
以上就是首页完成的显示的功能,篇幅有限,需要源码的朋友私聊我噢
千山万水总是情,打赏一元也是情
和老段一起终身学习,我们一起做自己的CEO!
有用吗?对于学完Spring、SpringMVC、Mybatis还无从下手的同学来说这是一个很好引子。对于正在学习同一个案例的同学,可能解决一些问题。对于需要这个案例的同学可以直接获取。
有什么?:xml配置文件编写,引入一个简单的前端框架,使用MyBatis Generator逆向工程生成一些代码,使用框架简单快速搭建一个页面,好用的分页工具PageHelper,简单的前后端分离,发送ajax请求,利用json传递数据,增、删、改、查的简单实现。
简单吗?内容很简单,涉及Java代码不多,但是对于新手来说,最困难的部分是各种环境搭建、配置文件、版本冲突,如果能够根据错误提示动手解决,那就是一大进步。
怎么学?如果有时间可以在B站搜索:ssm整合crud,雷丰阳讲的。如果想看到每个功能的实现过程和源码,可以在这里学习,每个步骤都有注释。也可以作为复习快速浏览。
前端格式校验、用户名校验、后端校验、JSR303校验,效果如图
使用弹出模态框作为新增模块,参考Bootstrap代码
<!-- 为新增按钮增加模态框 ,利用按钮绑定单击事件-->
<!-- Modal -->
<div class="modal fade" id="empAddModal" tabindex="-1" role="dialog"
aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">员工添加</h4>
</div>
<div class="modal-body">
<!-- 添加表单 -->
<form class="form-horizontal" id="model-form">
<!-- 姓名 -->
<div class="form-group">
<label for="empName_add_input" class="col-sm-2 control-label">EmpName</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="empName" id="empName_add_input"
placeholder="empName">
<!-- 用来显示错误提示 -->
<span class="help-block"></span>
</div>
</div>
<!-- 邮箱 -->
<div class="form-group">
<label for="email_add_input" class="col-sm-2 control-label">Email</label>
<div class="col-sm-10">
<input type="email" class="form-control" name="email" id="email_add_input"
placeholder="empName@123.com">
<!-- 用来显示错误提示 -->
<span class="help-block"></span>
</div>
</div>
<!-- 性别 -->
<div class="form-group">
<label class="col-sm-2 control-label">Gender</label>
<div class="col-sm-10">
<!-- 单选 -->
<label for="gender1_add_input"> <input type="radio"
name="gender" id="gender1_add_input"
name="gender" value="M" checked>
男
</label>
<label for="gender2_add_input"> <input type="radio"
name="gender" id="gender2_add_input"
name="gender" value="F">
女
</label>
</div>
</div>
<!-- 部门下拉框 -->
<div class="form-group">
<label class="col-sm-2 control-label">DeptName</label>
<div class="col-sm-10">
<!-- 部门下拉列表使用ajax查询出来的动态拼接,值为部门id -->
<select class="form-control" name="dId" id="deptName_add_select"></select>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="emp_save_btn">保存</button>
</div>
</div>
</div>
</div>
//添加模态栏 $("#emp_add_modal_btn").click(function() {
//显示模态框
$("#empAddModal").modal({
//模态框参数,点击背景不关闭
backdrop : "static"
});
});
//新增模态框 $("#emp_add_modal_btn").click(function() {
//添加模态栏之前将所表单信息清空,包括两项验证的css样式,显示模态栏之后就是空的
//reset()方法是dom下的,使用[0]
$("#empAddModal form")[0].reset();
//清空输入格式、重名校验的css样式
reset_form("#empAddModal form");
//获取所有部门信息
getDepts("#deptName_add_select");
//添加模态框,在模态框中需要所有部门,所以需要查询所有部门信息
$("#empAddModal").modal({
//模态框参数,点击背景不关闭
backdrop : "static"
});
});
//后面用
//新增模态框--清除表单数据,样式
function reset_form(ele) {
$(ele)[0].reset();
//该元素下所有css清除
$(ele).find("*").removeClass("has-error has-success");
//显示警告信息部分清空
$(ele).find(".help-block").text("");
}
//新增模态框--请求所有部门信息 function getDepts(ele){
//---注意这里要清空---
$(ele).empty();
$.ajax({
url:"${PATH}/depts",
type:"GET",
success:function(result){
//console.log(result);
//动态拼接
}
});
}
package com.ssm.controller;
import com.ssm.bean.Department;
import com.ssm.bean.Msg;
import com.ssm.service.DepartmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
/**
* 部门信息
*/
@Controller
public class DepartmentController {
@Autowired
private DepartmentService departmentService;
/**
* 获取所有部门信息
* @return
*/
@ResponseBody
@RequestMapping("/depts")
public Msg getDepts() {
List<Department> depts = departmentService.getDepts();
return Msg.success().add("depts", depts);
}
}
package com.ssm.service;
import com.ssm.bean.Department;
import com.ssm.dao.DepartmentMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 部门信息
*/
@Service
public class DepartmentService {
@Autowired
DepartmentMapper departmentMapper;
/**
* 查询所有部门
*/
public List<Department> getDepts(){
//方法本身可以添加查询条件,如果为null代表查所有
List<Department> list = departmentMapper.selectByExample(null);
return list;
}
}
//新增模态框--请求所有部门信息 function getDepts(ele){
//---注意这里要清空---
$(ele).empty();
$.ajax({
url:"${PATH}/depts",
type:"GET",
success:function(result){
//console.log(result);
$.each(result.extend.depts,function(index,item){
//创建出option并添加到select中
var optionEle = $("<option></option>").append(item.deptName).attr("value",item.deptId);
optionEle.appendTo(ele);
});
}
});
}
效果
绑定保存按钮
//------------------增删改查都使用REST风格------------------- //新增保存信息
$("#emp_save_btn").click(function(){
//1、模态框中填写的表单数据提交给服务器进行保存
//2、发送ajax请求保存员工
$.ajax({
url:"${PATH}/saveemp",
type:"POST",
data:$("#empAddModal form").serialize(),
//.serialize()方法能将表单中数据序列化,直接发送给controll封装成Bean
//console.log($("#empAddModal form").serialize());
//empName=Tom&email=Tom%40123.com&gender=M&dId=1
success:function(result){
//1.添加成功,关闭模态框
$("#empAddModal").modal("hide");
//2.来到最后一页,显示插入的数据,可以直接跳到一个很大的页数,因为
//合理性,所以不会超出,这里使用全局参数,数据总条数
to_page(totalRecord+1);
}
});
EmployeeController
@ResponseBody @RequestMapping(value = "/saveemp",method = RequestMethod.POST)
public Msg saveEmp(Employee employee, BindingResult result) {
employeeService.saveEmp(employee);
return Msg.success();
}
EmployeeService
/**
* 保存emp员工,insert
* @param employee
*/
public void saveEmp(Employee employee) {
//这个是有选择插入,insert()全插入,包括id
employeeMapper.insertSelective(employee);
}
一共有两种验证方式 1.输入框焦点单独验证 2.提交按钮总验证,为了不两种方式的css样式相互覆盖,每种方式都验两遍,格式在前,用户名在后
(内部Java格式验证)+ ajax用户名验证(实现方法看下一小节)
//1.(内部Java格式验证)+ ajax用户名验证 //新增保存信息--ajax用户名校验
//由于在java内又做了一次格式验证,所以这个方法相当于即验证了格式,又验证了重名
$("#empName_add_input").blur(function () {
//发送ajax请求,验证用户名是否可用
var empName = this.value;
$.ajax({
url: "${PATH}/checkname",
data: "empName=" + empName,
type: "POST",
success: function (result) {
console.log(result);
//获取到返回值,Msg中的状态码
if (result.code == 2333) {
show_validate_msg("#empName_add_input", "success", "用户名可用");
//因为使用了两种方式验证,格式和重名,会有css样式冲突覆盖,所以再加一次验证
//自定义属性,或全局变量
//给添加按钮添加自定义属性,在提交时判断是否通过两项验证。
$("#emp_save_btn").attr("ajax-vl", "success");
} else if (result.code == 5555) {
show_validate_msg("#empName_add_input", "error", result.extend.msg);
$("#emp_save_btn").attr("ajax-vl", "error");
}
}
});
});
邮箱格式独立校验
//2. 邮箱独立验证 //新增保存信息--独立邮箱格式验证
$("#email_add_input").blur(function () {
var email = $("#email_add_input").val();
var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
if (!regEmail.test(email)) {
//alert("邮箱格式不正确");
show_validate_msg("#email_add_input", "error", "邮箱格式不正确");
//return false;
} else {
show_validate_msg("#email_add_input", "success", "");
}
//最后方法通过
//return true;
})
格式+用户名验证+提交保存请求
//3. 格式+用户名验证+提交保存请求,一共有两种验证方式 1.输入框焦点单独验证 2.提交按钮总验证, //为了不两种方式的css样式相互覆盖,每种方式都验两遍,格式在前,用户名在后
//新增保存信息--请求
$("#emp_save_btn").click(function () {
//点击就发送请求,保存使用POST请求
//1.先验证ajax重名校验,防止用户输入重复用户名之后,直接输入正确的邮箱,点击提交,重名的验证提示会被覆盖
//ajax-vl是ajax重名校验之后添加的自定义属性,用于表示提交按钮是否可用
if ($(this).attr("ajax-vl") == "error") {
return false;
}
//2.点击保存按钮请求之前完整验证一遍输入格式
//JQuery格式总验证
if (!validate_add_form()) {
return false;
}
//3.重名验证
//ajax重名校验
if ($(this).attr("ajax-vl") == "error") {
return false;
}
//1、模态框中填写的表单数据提交给服务器进行保存
//2、发送ajax请求保存员工
$.ajax({
url: "${PATH}/saveemp",
type: "POST",
data: $("#empAddModal form").serialize(),
//.serialize()方法能将表单中数据序列化,直接发送给controll封装成Bean
//console.log($("#empAddModal form").serialize());
//empName=Tom&email=Tom%40123.com&gender=M&dId=1
success: function (result) {
//1.添加成功,关闭模态框
$("#empAddModal").modal("hide");
//2.来到最后一页,显示插入的数据,可以直接跳到一个很大的页数,因为
//合理性,所以不会超出,这里使用全局参数,参数值在上面分页时获取的,数据总条数+1保证不出现极端情况
to_page(totalRecord + 1);
}
});
});
请求按钮JQuery格式总校验方法
//新增保存信息--请求按钮JQuery格式总校验方法 function validate_add_form() {
console.log("validate_add_form()")
//1.拿到校验的数据,使用正则表达式
//根据bootstrap提供的组件
//校验用户名
var empName = $("#empName_add_input").val();
var regName = /(^[a-zA-Z0-9_-]{2,8}$)|(^[\u2E80-\u9FFF]{2,5})/;
if (!regName.test(empName)) {
//alert("用户名可以是2-5位中文或者2-8位英文和数字的组合");
show_validate_msg("#empName_add_input", "error", "用户名可以是2-5位中文或者2-8位英文和数字的组合");
return false;
} else {
show_validate_msg("#empName_add_input", "success", "");
}
//2、校验邮箱信息
var email = $("#email_add_input").val();
var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
if (!regEmail.test(email)) {
//alert("邮箱格式不正确");
show_validate_msg("#email_add_input", "error", "邮箱格式不正确");
return false;
} else {
show_validate_msg("#email_add_input", "success", "");
}
//最后方法通过
return true;
}
添加样式方法
//新增保存信息--添加css样式 //show_validate_msg显示校验状态,通过添加样式,ele表示被选择元素,status状态
//用来判断是用什么样式,绿色、红色,msg提示信息
function show_validate_msg(ele, status, msg) {
//判断之前先清空之前样式
$(ele).parent().removeClass("has-success has-error");
$(ele).next("span").text("");
if ("success" == status) {
$(ele).parent().addClass("has-success");
$(ele).next("span").text(msg)
} else if ("error" == status) {
$(ele).parent().addClass("has-error");
$(ele).next("span").text(msg)
}
}
如果添加相同的用户名会造成混淆,所以在输入用户名之后立即进行校验
发送ajax请求(与上一节相同)
$("#empName_add_input").blur(function () {
//发送ajax请求,验证用户名是否可用
var empName = this.value;
$.ajax({
url: "${PATH}/checkname",
data: "empName=" + empName,
type: "POST",
success: function (result) {
console.log(result);
//获取到返回值,Msg中的状态码
if (result.code == 2333) {
show_validate_msg("#empName_add_input", "success", "用户名可用");
//因为使用了两种方式验证,格式和重名,会有css样式冲突覆盖,所以再加一次验证
//自定义属性,或全局变量
//给添加按钮添加自定义属性,在提交时判断是否通过两项验证。
$("#emp_save_btn").attr("ajax-vl", "success");
} else if (result.code == 5555) {
show_validate_msg("#empName_add_input", "error", result.extend.msg);
$("#emp_save_btn").attr("ajax-vl", "error");
}
}
});
});
EmployeeController
/**
* 用户名查重
* 前端校验,在失去焦点,保存之前都校验
* @param empName
* @return
*/
@ResponseBody
@RequestMapping("/checkname")
public Msg checkEmpName(@RequestParam("empName")String empName) {
//用户名格式校验
String regx = "(^[a-zA-Z0-9_-]{2,8}$)|(^[\\u2E80-\\u9FFF]{2,5})";
if(!empName.matches(regx)){
return Msg.fail().add("msg", "用户名可以是2-5位中文或者2-8位英文和数字的组合");
}
//返回查询统计结果,true说明没有重名
boolean b = employeeService.checkEmpName(empName);
if(b) {
return Msg.success();
}else {
return Msg.fail().add("msg", "用户名已存在");
}
}
EmployeeService
/**
* 查询用户是否存在
* 使用Example复杂查询
*
* @param name
* @return
*/
public boolean checkEmpName(String name) {
//Example用法
EmployeeExample example = new EmployeeExample();
//创建查询条件
EmployeeExample.Criteria criteria = example.createCriteria();
//我的理解:这一句相当于添加了一个条件 where empName=name
criteria.andEmpNameEqualTo(name);
//统计查询结构
long count = employeeMapper.countByExample(example);
//返回true(0)说明没有重复用户名
return count == 0;
}
前面是前端校验,现在是后端校验,针对Java
添加JSR303依赖
<!-- JSR303校验 -->
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.0.Final</version>
</dependency>
在JavaBean上添加注解
public class Employee {
private Integer empId;
//JSR303自定义校验规则
@Pattern(regexp = "(^[a-zA-Z0-9_-]{2,8}$)|(^[\\u2E80-\\u9FFF]{2,5})", message = "用户名可以是2-5位中文或者2-8位英文和数字的组合")
private String empName;
private String gender;
@Pattern(regexp = "^([a-z0-9_\\.-]+)@([\\da-z\\.-]+)\\.([a-z\\.]{2,6})$",message = "邮箱格式不正确")
private String email;
//...
在Controller方法中使用,在参数前添加注解,在参数后面添加结果参数
/**
* 新增,保存用户,并验证
*
* 添加JSR303校验
* @Valid表示校验下一个对象
* BindingResult紧跟被校验对象,接收结果
*
* @param employee
* @return
*/
@ResponseBody
@RequestMapping(value = "/saveemp",method = RequestMethod.POST)
public Msg saveEmp(@Valid Employee employee, BindingResult result) {
if(result.hasErrors()) {
//格式校验失败,返回信息
Map<String ,Object> map = new HashMap<>();
List<FieldError> fieldErrors = result.getFieldErrors();
for(FieldError error : fieldErrors) {
System.out.println("错误的字段名:" + error.getField());
System.out.println("错误信息:" + error.getDefaultMessage());
//将错误信息放到map中
map.put(error.getField(), error.getDefaultMessage());
}
return Msg.fail().add("errorFields", map);
}else if(!employeeService.checkEmpName(employee.getEmpName())){
//后端在保存的时候再次验证是否存在用户名---有点 重复的感觉???
//因为是在一起接收所以错误信息一定要一样,empName手动写上
return Msg.fail().add("empName", "用户名已存在");
}else {
employeeService.saveEmp(employee);
//不用这种:获取总页数,用在新增完之后跳转到最后一页,不过这样就会多查一次数据库
//PageInfo<Employee> pageInfo = employeeService.getPage(null);
//return Msg.success().add("pageInfo", pageInfo);
return Msg.success();
}
}
在index.jsp提交按钮中处理返回结果
//3. 格式+用户名验证+提交保存请求,一共有两种验证方式 1.输入框焦点单独验证 2.提交按钮总验证, //为了不两种方式的css样式相互覆盖,每种方式都验两遍,格式在前,用户名在后
//新增保存信息--请求
$("#emp_save_btn").click(function () {
//点击就发送请求,保存使用POST请求
//1.先验证ajax重名校验,防止用户输入重复用户名之后,直接输入正确的邮箱,点击提交,重名的验证提示会被覆盖
if ($(this).attr("ajax-vl") == "error") {
return false;
}
//2.点击保存按钮请求之前完整验证一遍输入格式
console.log("JQuery格式总验证")
//方法一:JQuery格式总验证
if (!validate_add_form()) {
return false;
}
//3.重名验证
console.log("ajax重名校验")
//ajax重名校验
if ($(this).attr("ajax-vl") == "error") {
return false;
}
//1、模态框中填写的表单数据提交给服务器进行保存
//2、发送ajax请求保存员工
$.ajax({
url: "${PATH}/saveemp",
type: "POST",
data: $("#empAddModal form").serialize(),
//.serialize()方法能将表单中数据序列化,直接发送给controll封装成Bean
//console.log($("#empAddModal form").serialize());
//empName=Tom&email=Tom%40123.com&gender=M&dId=1
success: function (result) {
//清除模态框和提示信息
$("#empAddModal form").find("*").removeClass("has-error has-success");
$("#empAddModal form").find(".help-block").text("");
//在这里判断后端JSR303校验结果,最后一次!!!!!!!!!真的
//前后端验证可以独立运行,注释前端后端也能实现一样效果
if(result.code == 2333){
//alert(result.msg);
//1.添加成功,关闭模态框
$("#empAddModal").modal("hide");
//2.来到最后一页,显示插入的数据,可以直接跳到一个很大的页数,因为
//合理性,所以不会超出,这里使用全局参数,数据总条数+1保证不出现极端情况
to_page(totalRecord + 1);
}else{
//失败,显示信息,有几个就显示几个
//undefined 就是没找到这个错误,说明正确,可用alert(result.extend.errorFields.empName)验证
//用户名格式
//alert(result.extend.errorFields.empName)
//用户名格式和查重,因为查重的属性格式和格式验证不同,所以不能分开
//result.extend.errorFields.empName 格式验证
//result.extend.empName 查重验证
if(undefined != result.extend.errorFields ){
//格式错误
if(undefined != result.extend.errorFields.empName){
show_validate_msg("#empName_add_input","error",result.extend.errorFields.empName);
}
}else{
if(undefined != result.extend.empName){
//查重错误
show_validate_msg("#empName_add_input","error",result.extend.empName);
}
}
//邮箱格式判断
if(undefined != result.extend.errorFields){
if(undefined != result.extend.errorFields.email){
show_validate_msg("#email_add_input","error",result.extend.errorFields.email);
}
}
}
}
});
});
模态框
<!-- 为新增按钮增加模态框 ,利用按钮绑定单击事件-->
<!-- Modal -->
<div class="modal fade" id="empAddModal" tabindex="-1" role="dialog"
aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">员工添加</h4>
</div>
<div class="modal-body">
<!-- 添加表单 -->
<form class="form-horizontal" id="model-form">
<!-- 姓名 -->
<div class="form-group">
<label for="empName_add_input" class="col-sm-2 control-label">EmpName</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="empName" id="empName_add_input"
placeholder="empName">
<!-- 用来显示错误提示 -->
<span class="help-block"></span>
</div>
</div>
<!-- 邮箱 -->
<div class="form-group">
<label for="email_add_input" class="col-sm-2 control-label">Email</label>
<div class="col-sm-10">
<input type="email" class="form-control" name="email" id="email_add_input"
placeholder="empName@123.com">
<!-- 用来显示错误提示 -->
<span class="help-block"></span>
</div>
</div>
<!-- 性别 -->
<div class="form-group">
<label class="col-sm-2 control-label">Gender</label>
<div class="col-sm-10">
<!-- 单选 -->
<label for="gender1_add_input"> <input type="radio"
name="gender" id="gender1_add_input"
name="gender" value="M" checked>
男
</label>
<label for="gender2_add_input"> <input type="radio"
name="gender" id="gender2_add_input"
name="gender" value="F">
女
</label>
</div>
</div>
<!-- 部门下拉框 -->
<div class="form-group">
<label class="col-sm-2 control-label">DeptName</label>
<div class="col-sm-10">
<!-- 部门下拉列表使用ajax查询出来的动态拼接,值为部门id -->
<select class="form-control" name="dId" id="deptName_add_select"></select>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="emp_save_btn">保存</button>
</div>
</div>
</div>
</div>
请求和方法
<script type="text/javascript">
//------------------增删改查都使用REST风格-------------------
//1.(内部Java格式验证)+ ajax用户名验证
//新增保存信息--ajax用户名校验
//由于在java内又做了一次格式验证,所以这个方法相当于即验证了格式,又验证了重名
$("#empName_add_input").blur(function () {
//发送ajax请求,验证用户名是否可用
var empName = this.value;
$.ajax({
url: "${PATH}/checkname",
data: "empName=" + empName,
type: "POST",
success: function (result) {
console.log(result);
//获取到返回值,Msg中的状态码
if (result.code == 2333) {
show_validate_msg("#empName_add_input", "success", "用户名可用");
//因为使用了两种方式验证,格式和重名,会有css样式冲突覆盖,所以再加一次验证
//自定义属性,或全局变量
//给添加按钮添加自定义属性,在提交时判断是否通过两项验证。
$("#emp_save_btn").attr("ajax-vl", "success");
} else if (result.code == 5555) {
show_validate_msg("#empName_add_input", "error", result.extend.msg);
$("#emp_save_btn").attr("ajax-vl", "error");
}
}
});
});
//2. 邮箱独立验证
//新增保存信息--独立邮箱格式验证
$("#email_add_input").blur(function () {
var email = $("#email_add_input").val();
var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
if (!regEmail.test(email)) {
//alert("邮箱格式不正确");
show_validate_msg("#email_add_input", "error", "邮箱格式不正确");
//return false;
} else {
show_validate_msg("#email_add_input", "success", "");
}
//最后方法通过
//return true;
})
//3. 格式+用户名验证+提交保存请求,一共有两种验证方式 1.输入框焦点单独验证 2.提交按钮总验证,
//为了不两种方式的css样式相互覆盖,每种方式都验两遍,格式在前,用户名在后
//新增保存信息--请求
$("#emp_save_btn").click(function () {
//点击就发送请求,保存使用POST请求
//1.先验证ajax重名校验,防止用户输入重复用户名之后,直接输入正确的邮箱,点击提交,重名的验证提示会被覆盖
if ($(this).attr("ajax-vl") == "error") {
return false;
}
//2.点击保存按钮请求之前完整验证一遍输入格式
console.log("JQuery格式总验证")
//方法一:JQuery格式总验证
if (!validate_add_form()) {
return false;
}
//3.重名验证
console.log("ajax重名校验")
//ajax重名校验
if ($(this).attr("ajax-vl") == "error") {
return false;
}
//1、模态框中填写的表单数据提交给服务器进行保存
//2、发送ajax请求保存员工
$.ajax({
url: "${PATH}/saveemp",
type: "POST",
data: $("#empAddModal form").serialize(),
//.serialize()方法能将表单中数据序列化,直接发送给controll封装成Bean
//console.log($("#empAddModal form").serialize());
//empName=Tom&email=Tom%40123.com&gender=M&dId=1
success: function (result) {
//清除模态框和提示信息
$("#empAddModal form").find("*").removeClass("has-error has-success");
$("#empAddModal form").find(".help-block").text("");
//在这里判断后端JSR303校验结果,最后一次!!!!!!!!!真的
//前后端验证可以独立运行,注释前端后端也能实现一样效果
if(result.code == 2333){
//alert(result.msg);
//1.添加成功,关闭模态框
$("#empAddModal").modal("hide");
//2.来到最后一页,显示插入的数据,可以直接跳到一个很大的页数,因为
//合理性,所以不会超出,这里使用全局参数,数据总条数+1保证不出现极端情况
to_page(totalRecord + 1);
}else{
//失败,显示信息,有几个就显示几个
//undefined 就是没找到这个错误,说明正确,可用alert(result.extend.errorFields.empName)验证
//用户名格式
//alert(result.extend.errorFields.empName)
//用户名格式和查重,因为查重的属性格式和格式验证不同,所以不能分开
//result.extend.errorFields.empName 格式验证
//result.extend.empName 查重验证
if(undefined != result.extend.errorFields ){
//格式错误
if(undefined != result.extend.errorFields.empName){
show_validate_msg("#empName_add_input","error",result.extend.errorFields.empName);
}
}else{
if(undefined != result.extend.empName){
//查重错误
show_validate_msg("#empName_add_input","error",result.extend.empName);
}
}
//邮箱格式判断
if(undefined != result.extend.errorFields){
if(undefined != result.extend.errorFields.email){
show_validate_msg("#email_add_input","error",result.extend.errorFields.email);
}
}
}
}
});
});
//新增保存信息--请求按钮JQuery格式总校验方法
function validate_add_form() {
console.log("validate_add_form()")
//1.拿到校验的数据,使用正则表达式
//根据bootstrap提供的组件
//校验用户名
var empName = $("#empName_add_input").val();
var regName = /(^[a-zA-Z0-9_-]{2,8}$)|(^[\u2E80-\u9FFF]{2,5})/;
if (!regName.test(empName)) {
//alert("用户名可以是2-5位中文或者2-8位英文和数字的组合");
show_validate_msg("#empName_add_input", "error", "用户名可以是2-5位中文或者2-8位英文和数字的组合");
return false;
} else {
show_validate_msg("#empName_add_input", "success", "");
}
//2、校验邮箱信息
var email = $("#email_add_input").val();
var regEmail = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/;
if (!regEmail.test(email)) {
//alert("邮箱格式不正确");
show_validate_msg("#email_add_input", "error", "邮箱格式不正确");
return false;
} else {
show_validate_msg("#email_add_input", "success", "");
}
//最后方法通过
return true;
}
//新增保存信息--添加css样式
//show_validate_msg显示校验状态,通过添加样式,ele表示被选择元素,status状态
//用来判断是用什么样式,绿色、红色,msg提示信息
function show_validate_msg(ele, status, msg) {
//判断之前先清空之前样式
$(ele).parent().removeClass("has-success has-error");
$(ele).next("span").text("");
if ("success" == status) {
$(ele).parent().addClass("has-success");
$(ele).next("span").text(msg)
} else if ("error" == status) {
$(ele).parent().addClass("has-error");
$(ele).next("span").text(msg)
}
}
</script>
__EOF__
本文作者: 蔚然丶丶
本文链接: https://www.cnblogs.com/wei-ran/p/16131419.html
页篡改是最为常见的一种黑客攻击形式。网页篡改是一种通过网页应用中的漏洞获取权限,非法篡改Web应用中的内容、植入暗链、传播恶意信息,危害社会安全并牟取暴利的网络攻击行为。
近些年来,网页篡改攻击事件层出不穷,且具有以下四个特点:篡改网站页面传播速度快、阅读人群多;篡改页面容易,预先检查、实时防范、事后消除影响难;网络环境复杂,追查责任难;攻击工具简单,并且向智能化趋势发展。
零时代:人工对比检测
人工对比检测,其实就是一种专门指派网络管理人员,人工监控需要保护的网站,一旦发现被篡改,然后以人力对其修改还原的手段。严格说来,人工对比检测不能算是一种网页防篡改系统采用的技术,而只能算是一种原始的应对网页被篡改的手段。但是其在网页防篡改的技术发展历程中存在一段相当久的时间。
这种手段非常原始且效果不佳,且不说人力成本较高,其最致命的缺陷在于人力监控不能达到即时性,也就是不能在第一时间发现网页被篡改,也不能在第一时间做出还原,当管理人员发现网页被篡改再做还原时,被篡改的网页已在互联网存在了一段时间,可能已经被一定数量的网民浏览,造成一定的负面影响。
第一代:时间轮询技术
时间轮询技术,也称“外挂轮询技术”。从这一代开始,网页防篡技术已经摆脱了以人力检测恢复为主体的原始手段,而是作为一种自动化的技术形式出现。时间轮询技术是利用一个网页检测程序,以轮询方式读出要监控的网页,与真实网页相比较后,进行判断网页内容的完整性,对于被篡改的网页进行报警和恢复。
采用时间轮询式的网页防篡改系统,对每个网页来说,轮询扫描存在着时间间隔,一般为数十分钟。所以,在这数十分钟的间隔中,黑客可以攻击系统并使访问者访问到被篡改的网页。
此类应用在过去网页访问量较少,具体网页应用较少的情况下适用,目前网站页面通常少则上百页,检测轮询时间更长,且占用系统资源较大,该技术逐渐被淘汰。
第二代:事件触发+核心内嵌技术
将事件触发技术与核心内嵌技术两种技术放在同一代来说,是因为这两种网页防篡改技术出现的时间差距不大,而且两种技术常常被结合使用。
所谓核心内嵌技术,即密码水印技术,最初先将网页内容采取非对称加密存放,在外来访问请求时将经过加密验证过的,进行解密对外发布,若未经过验证,则拒绝对外发布,调用备份网站文件进行验证解密后对外发布。此种技术通常要结合事件触发机制对文件的部分属性进行对比,如大小、页面生成时间等做判断,无法更准确的进行其它属性的判断。其最大的特点就是相对外挂轮询技术安全性大大提高,但其美中不足是加密计算会占用大量服务器资源,系统反映较慢。
核心内嵌技术避免了时间轮询技术的轮询间隔这个缺点。但是由于这种技术是对每个流出网页都进行完整检查,占用巨大的系统资源,给服务器造成较大负载。而且,因为对网页正常发布流程作了更改,整个网站需要重新架构,增加新的发布服务器替代原先的服务器。
随着IT技术发展以及网上各类应用的增多,对服务器的负载资源简直可以用“苛刻”来形容,任何占用服务器资源的部分都要淘汰,来确保网站的高效率访问和网页防篡改技术追踪率,如此一来,内嵌技术最终也被淘汰。
第三代:过滤驱动+事件触发技术
技术发展到二十一世纪初,第三代文件网页防篡技术:过滤驱动+事件触发技术应运而生。
文件过滤驱动技术的最初应用于保密系统,作为文件保护技术和各类审计技术,甚至被应用于“流氓软件”。在网页防篡改技术革新当中,该技术找到了其发展的空间。与事件触发技术结合,形成了第三代网页防篡改保护技术。
其原理是将篡改监测的核心程序,利用微软文件底层驱动技术应用到Web服务器中,通过事件触发方式,对文件夹的所有文件内容,对照其底层文件属性,经过内置散列快速算法,实时进行监测。若发现属性变更,则通过非协议方式,将纯文件安全拷贝,备份路径文件夹内容拷贝到监测文件夹相应文件位置,通过底层文件驱动技术,整个文件复制过程毫秒级,使得公众无法看到被篡改页面,其运行性能和检测实时性都达到较高水准。该页面防篡改模块采用Web服务器底层文件过滤驱动级保护技术,与操作系统紧密结合,所监测的文件类型不限,可以是一个html文件,也可以是一段动态代码,执行准确率较高。
这样就不仅完全杜绝了轮询扫描式页面,防篡改软件的扫描间隔中被篡改内容被访问的可能,其所消耗的内存和CPU占用率也远远低于文件轮询扫描式或核心内嵌式的同类软件。可以说是一种简单、高效、安全性又极高的防篡改技术。
第四代:“五重防护”技术
目前,国内专注于保密与非密领域的分级保护、等级保护、业务连续性安全和大数据安全产品解决方案与相关技术研究开发的领军企业——国联易安更是基于“高效同步”、“安全传输”两项技术,研发出了具备独特的“五重防护”新特性,支持网页的全自动发布、网页监控、报警和自动恢复,提供强大的网页安全管理维护功能的网页防篡改保护系统。
一重防护:实时阻断。系统能够阻断对受保护网页的非法操作,此项技术有效地甄别合法进程和非法进程,阻断非法进程对网页的篡改,将非法进程直接阻断。
二重防护:事件触发。系统具备触发式检验引擎,针对受保护的文件增删改操作,一触即发,校验修改的合法性,瞬间清除被非法篡改的网页,实时恢复合法网页。
三重防护:核心内嵌。系统内嵌式篡改检测引擎运行于Web服务器内部,与Web服务器无缝结合。系统检测每一个Web请求访问页面,进行水印校验,确保发送网页的正确性。
四重防护:主动阻断。当网站受到持续性攻击时,系统会自动启动积极防御机制,从根本上阻断来自外部的攻击。
五重防护:木马检测与查杀。系统提供对被保护网页是否已经中木马的检测能力,如果已经中木马可以查杀清除。对未中木马的网页,能提供防止挂木马的防护能力。
结语
网页防篡改主要有两大功能:一是对攻击事件进行监测与防护,二是网页被篡改后实现快速恢复。
网页相当于是一个组织机构的脸面,如果发生了黑客恶意篡改网页,造成恶性事件,将对组织机构形象造成严重负面影响。因此,无论在日常的网络安全加固,还是在等保评测过程中,网页防篡改防护均被提到重要高度,成为一个政府、企事业单位必须采购的网络安全产品。
值得一提的是,虽然Web防火墙WAF也能够在日常的安全运营中发挥作用,但WAF不能替代网页防篡改产品。因为有黑客有太多的办法可以绕过WAF,造成网站被攻击。惟有网页防篡改产品才能真正防止网页篡改恶性事件发生,或者在事后对网页快速恢复。
关于国联易安
北京国联易安信息技术有限公司(原北京智恒联盟科技有限公司)简称“国联易安”,成立于2006年,拥有“国联易安”和“智恒联盟”两个品牌,是国内专注于保密与非密领域的分级保护、等级保护、业务连续性安全和大数据安全产品解决方案与相关技术研究开发的领军企业。公司多项安全技术补了国内技术空白,并且在政府、金融、保密、电信运营商、军队军工、大中型企业、能源、教育、医疗电商等领域得到广泛应用。
国联易安除研发生产专业安全产品外,还为客户提供全面的检测与防护方案专家咨询、源代码安全评估、安全运维值守、智能终端安全评估、安全渗透测试、专业安全培训等专业安全服务。
*请认真填写需求信息,我们会在24小时内与您取得联系。