ssm高级注解开发(商品增删改查,图片上传等)

前言

在学习了Spring4+SpringMVC+mybatis整合以及ssm简单使用后,我们已经基本掌握ssm开发的基础知识,下面将进行ssm高级注解开发,包括的知识有:包装类型pojo参数绑定(即类中不是简单类型的属性,而是另外的pojo),list参数绑定,数据回显,上传图片,json交互,RESTful架构,拦截器等

此次开发是基于上面两篇文章中的项目实现的,上面两篇文章的项目源码请到我的github项目下载

添加按商品名称查询功能

我们已经在mapper包下的ItemsCustomMapper中定义了根据名称来查询的sql片段,
接下来,我们需要在controller类中的queryItems方法绑定ItemsQueryVo对象(即包装类型pojo对象)

原来的queryItems方法

@RequestMapping("/queryItems")
public ModelAndView queryItems() throws Exception{
    List<ItemCustom> itemsList=itemsService.findItemsList(null);

改为

@RequestMapping("/queryItems")
public ModelAndView queryItems(ItemsQueryVo itemsQueryVo) throws Exception{
    //形参上传入了ItemsQueryVo对象,并将形参传入service的findItemsList方法中
    List<ItemCustom> itemsList=itemsService.findItemsList(itemsQueryVo);
在itemsList.jsp页面中对应添加商品名称的查询条件(input输入框)
<form class="layui-form" action="${pageContext.request.contextPath}/items/queryItems.action" method="post">
    <label class="layui-form-label">查询条件</label>
    <div class="layui-input-block">
        <label class="layui-form-label">商品名称</label>
        <div class="layui-input-inline">
<%-- 注意:这里传入的是ItemsQueryVo类下的pojo类ItemCustom下的name属性 --%>
            <input class="layui-input" type="text" name="itemCustom.name">
        </div>
        <div class="layui-input-inline">
            <button class="layui-btn" type="submit" value="查询">查询</button>
        </div>
    </div>
</form>

这里只是取ItemsQueryVo类下的ItemCustom的name属性,若有多层包装类,则按照
类名.类名.(...).属性来命名form表单所要传入参数
然后,只要在商品显示页面的商品名称输入框输入所要查找的商品名称,就可以看到相应结果

新增添加商品信息功能

在mapper包下的ItemsMapper.xml下已经编写好往数据库插入记录的insert语句,
由于我这里使用的是sqlserver的id自增类型,不允许再插入id值,需要修改一下
insert语句(使用mysql的自增类型则不用修改),如下:


将body中form表单部分改为
<form class="layui-form" action="${pageContext.request.contextPath}/items/queryItems.action" method="post">
    <label class="layui-form-label">查询条件</label>
    <div class="layui-input-block">
        <label class="layui-form-label">商品名称</label>
        <div class="layui-input-inline">
<%-- 注意:这里传入的是ItemsQueryVo类下的pojo类ItemCustom下的name属性 --%>
            <input class="layui-input" type="text" name="itemCustom.name">
        </div>
        <div class="layui-input-inline">
            <button class="layui-btn" type="submit" value="查询">查询</button>
        </div>
    </div>
</form>

这里只是取ItemsQueryVo类下的ItemCustom的name属性,若有多层包装类,则按照
类名.类名.(...).属性来命名form表单所要传入参数
然后,只要在商品显示页面的商品名称输入框输入所要查找的商品名称,就可以看到相应结果

新增添加商品信息功能

在mapper包下的ItemsMapper.xml下已经编写好往数据库插入记录的insert语句,
由于我这里使用的是sqlserver的id自增类型,不允许再插入id值,需要修改一下
insert语句(使用mysql的自增类型则不用修改),如下:

<!--<insert id="insert" parameterType="po.Items">-->
  <!--insert into items (id, name, price, -->
    <!--detail, pic, createtime-->
    <!--)-->
  <!--values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{price,jdbcType=NUMERIC}, -->
    <!--#{detail,jdbcType=VARCHAR}, #{pic,jdbcType=VARCHAR}, #{createtime,jdbcType=TIMESTAMP}-->
    <!--)-->
<!--</insert>-->
<!--<insert id="insertSelective" parameterType="po.Items">-->
  <!--insert into items-->
  <!--<trim prefix="(" suffix=")" suffixOverrides=",">-->
    <!--<if test="id != null">-->
      <!--id,-->
    <!--</if>-->
    <!--<if test="name != null">-->
      <!--name,-->
    <!--</if>-->
    <!--<if test="price != null">-->
      <!--price,-->
    <!--</if>-->
    <!--<if test="detail != null">-->
      <!--detail,-->
    <!--</if>-->
    <!--<if test="pic != null">-->
      <!--pic,-->
    <!--</if>-->
    <!--<if test="createtime != null">-->
      <!--createtime,-->
    <!--</if>-->
  <!--</trim>-->
  <!--<trim prefix="values (" suffix=")" suffixOverrides=",">-->
    <!--<if test="id != null">-->
      <!--#{id,jdbcType=INTEGER},-->
    <!--</if>-->
    <!--<if test="name != null">-->
      <!--#{name,jdbcType=VARCHAR},-->
    <!--</if>-->
    <!--<if test="price != null">-->
      <!--#{price,jdbcType=NUMERIC},-->
    <!--</if>-->
    <!--<if test="detail != null">-->
      <!--#{detail,jdbcType=VARCHAR},-->
    <!--</if>-->
    <!--<if test="pic != null">-->
      <!--#{pic,jdbcType=VARCHAR},-->
    <!--</if>-->
    <!--<if test="createtime != null">-->
      <!--#{createtime,jdbcType=TIMESTAMP},-->
    <!--</if>-->
  <!--</trim>-->
<!--</insert>-->

<!-- 因为id在sqlserver设置为自增型的id,不需要再插入,这里改写一下insert的sql语句,将上面一段注释掉 -->
<!-- 即在insert中不插入id值 -->
<insert id="insert" parameterType="po.Items">
  insert into items (name, price,
  detail, pic, createtime
  )
  values (#{name,jdbcType=VARCHAR}, #{price,jdbcType=NUMERIC},
  #{detail,jdbcType=VARCHAR}, #{pic,jdbcType=VARCHAR}, #{createtime,jdbcType=TIMESTAMP}
  )
</insert>
<insert id="insertSelective" parameterType="po.Items">
  insert into items
  <trim prefix="(" suffix=")" suffixOverrides=",">
    <if test="id != null">
      id,
    </if>
    <if test="name != null">
      name,
    </if>
    <if test="price != null">
      price,
    </if>
    <if test="detail != null">
      detail,
    </if>
    <if test="pic != null">
      pic,
    </if>
    <if test="createtime != null">
      createtime,
    </if>
  </trim>
  <trim prefix="values (" suffix=")" suffixOverrides=",">
    <if test="id != null">
      #{id,jdbcType=INTEGER},
    </if>
    <if test="name != null">
      #{name,jdbcType=VARCHAR},
    </if>
    <if test="price != null">
      #{price,jdbcType=NUMERIC},
    </if>
    <if test="detail != null">
      #{detail,jdbcType=VARCHAR},
    </if>
    <if test="pic != null">
      #{pic,jdbcType=VARCHAR},
    </if>
    <if test="createtime != null">
      #{createtime,jdbcType=TIMESTAMP},
    </if>
  </trim>
</insert>

修改完成后,在service包下的ItemsService新增addItems方法


//添加商品
public void addItems(ItemCustom itemCustom) throws Exception;

在service/impl包下的ItemsServiceImpl重写addItems方

@Override
public void addItems(ItemCustom itemCustom) throws Exception{
    // 添加商品
    //使用itemsMapper中的insert方法来插入记录
    itemsMapper.insert(itemCustom);
}

在controller包下的ItemsController设置相应的跳转路径

//跳转到添加商品的jsp页面
@RequestMapping("/addItems")
public String add() throws Exception{
    return "addItems";
}

// 提交添加商品请求
@RequestMapping("/addItemsSubmit")
public String addSuccess(ItemCustom itemCustom) throws Exception{
    //编写添加商品的功能
    itemsService.addItems(itemCustom);

    return "forward:addItems.action";
}

在controller中指定了addItems.jsp页面,路径是WEB-INF/jsp/addItems.jsp

<%--
  Created by IntelliJ IDEA.
  User: 光玉
  Date: 2018/4/10
  Time: 20:39
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="utf-8" %>

<html>
<head>
    <title>添加商品</title>
    <script type="text/javascript" src="<%= request.getContextPath()%>/plugin/layui/layui.all.js"></script>
    <link rel="stylesheet" href="<%= request.getContextPath()%>/plugin/layui/css/layui.css">
</head>

<!-- 由于在前端itemsList.jsp使用弹出层将表单传入,
    提交按钮也绑定到弹出层的“添加”按钮,这里便不编写“提交”按钮 -->
<body style="background-color: #7e6c75">
<form id="formSubmit" class="layui-form" action="${pageContext.request.contextPath}/items/addItemsSubmit.action" method="post">
    <div class="layui-form-item">
        <label class="layui-form-label">商品名称</label>
        <div class="layui-input-block">
            <input class="layui-input" type="text" name="name" placeholder="必须填写此字段"/>
        </div>
    </div>

    <div class="layui-form-item">
        <label class="layui-form-label">商品价格</label>
        <div class="layui-input-block">
            <input class="layui-input" type="text" name="price" placeholder="必须填写此字段"/>
        </div>
    </div>

    <%--<div class="layui-form-item">
        <label class="layui-form-label">商品图片</label>
        <div class="layui-input-inline">
            <input class="layui-input" type="text" name="pic"/>
        </div>
    </div>--%>

    <div class="layui-form-item">
        <label class="layui-form-label">生产日期</label>
        <div class="layui-input-block">
            <input class="layui-input" type="text" name="createtime" placeholder="必填,格式为yyyy-MM-dd HH:mm:ss"/>
        </div>
    </div>

    <div class="layui-form-item layui-form-text">
        <label class="layui-form-label">商品详情</label>
        <div class="layui-input-block">
            <textarea class="layui-textarea" name="detail"></textarea>
        </div>
    </div>

    <%--<div class="layui-form-item">--%>
        <%--<div class="layui-input-block">--%>
            <%--<button class="layui-btn" type="submit">提交</button>--%>
            <%--<button type="reset" class="layui-btn layui-btn-primary">重置</button>--%>
        <%--</div>--%>
    <%--</div>--%>
</form>

<script>
    layui.use('form', function () {
        var form = layui.form;
        form.render();
    });
</script>

</body>
</html>

由于下面还要编写批量删除和批量修改功能,所以显示页面itemsList.jsp在编写完批量删除功能后再给出修改后的代码

新增批量删除功能

同样的道理,需要编写ItemsService,ItemsServiceImpl和ItemsController
ItemsService下添加如下代码:

//删除商品
public void deleteItemsById(Integer id) throws Exception;

ItemsServiceImpl下添加如下代码:

@Override
public void deleteItemsById(Integer id) throws Exception{
    // 删除商品
    //使用itemsMapper中的deleteByPrimaryKey方法来删除商品
    itemsMapper.deleteByPrimaryKey(id);
}

ItemsController下添加如下代码:

// 批量删除商品
@RequestMapping("/deleteItems")
public String deleteItems(Integer[] item_id) throws Exception{
    // 传入参数类型为商品的id数组
    // 根据id批量删除商品
    for(int i=0;i<item_id.length;i++){
        itemsService.deleteItemsById(item_id[i]);
    }
    // 完成删除操作后重定向回显示页面
    return "forward:queryItems.action";
}

注意:这里传入的是Integer类型的数组,即绑定数组类型
其实和简单类型一样,这里没有用@RequestParam,所以形参名称必须和
前端jsp传过来的参数名称一样(这里是checkbox复选框的name属性)

新增批量修改功能

我们要对数据进行批量修改操作时,通常要用到List集合来存储相关信息
比如我们要获取批量修改过的商品信息,这时就需要绑定List集合参数来实现
注意:不能直接在形参中定义List,要在包装类中声明List

在ItemQueryVo中声明List集合

//批量修改商品的列表
private List<ItemCustom> itemsList;

public List<ItemCustom> getItemsList() {
    return itemsList;
}

public void setItemsList(List<ItemCustom> itemsList) {
    this.itemsList = itemsList;
}

ItemsController添加如下两个方法

// 跳转到批量修改商品页面
@RequestMapping("/editQueryItems")
public ModelAndView editQueryItems(ItemsQueryVo itemsQueryVo) throws Exception{

    List<ItemCustom> itemsList=itemsService.findItemsList(itemsQueryVo);

    ModelAndView modelAndView=new ModelAndView();   //创建视图对象
    modelAndView.addObject("itemsList",itemsList);

    modelAndView.setViewName("editQueryItems");  //指定用户访问的jsp页面地址,前缀和后缀已在前端控制器中配好
    return modelAndView;
}

//批量修改提交后
@RequestMapping("/editQueryItemsSubmit")
public String editQueryItemsSubmit(ItemsQueryVo itemsQueryVo) throws Exception{

    // 获取装有客户表的信息
    List<ItemCustom> editItemsList=itemsQueryVo.getItemsList();
    Integer editId;
    ItemCustom editItem;
    // 更新信息
    // 根据前端传过来的id修改相应内容
    for(int i=0;i<editItemsList.size();i++){
        editId=editItemsList.get(i).getId();
        editItem=editItemsList.get(i);
        itemsService.updateItems(editId,editItem);
    }
    return "forward:queryItems.action";
}

此时商品查询页面ItemsList.jsp的代码为:

<%--
  Created by IntelliJ IDEA.
  User: 光玉
  Date: 2018/4/3
  Time: 18:35
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<!DOCTYPE html>
<head>
    <title>查询商品列表</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script type="text/javascript" src="<%= request.getContextPath()%>/plugin/layui/layui.all.js"></script>
    <link rel="stylesheet" href="<%= request.getContextPath()%>/plugin/layui/css/layui.css">
</head>

<body>
<div style="margin-left: 250px">
    <form name="itemsForm" class="layui-form" action="${pageContext.request.contextPath}/items/queryItems.action" method="post">
        <label class="layui-form-label">查询条件</label>
        <div class="layui-input-block">
            <label class="layui-form-label">商品名称</label>
            <div class="layui-input-inline">
                <input class="layui-input" type="text" name="itemCustom.name" placeholder="请输入关键字">
            </div>
            <div class="layui-input-inline">
                <button class="layui-btn" type="submit" id="find">查询</button>
            </div>
            <div class="layui-input-inline">
                <button class="layui-btn layui-btn-normal" type="button" id="add">添加商品</button>
            </div>
            <div class="layui-input-inline">
                <button class="layui-btn layui-btn-danger" type="button" id="delete">批量删除</button>
            </div>
            <div class="layui-input-inline">
                <button class="layui-btn layui-btn-normal" type="button" id="editQuery">批量修改</button>
            </div>
        </div>

        <div style="width: 900px">
            <table class="layui-table" lay-size="sm">
                <thead>
                <th>批量删除</th>
                <th>商品名称</th>
                <th>商品价格</th>
                <th>商品详情</th>
                <th>生产日期</th>
                <th>操作</th>
                </thead>
                <tbody>
                <c:forEach items="${itemsList}" var="item">
                    <tr>
                        <td><input type="checkbox" name="item_id" value="${item.id}"/> </td>
                        <td>${item.name}</td>
                        <td>${item.price}</td>
                        <td>${item.detail}</td>
                        <td><fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/> </td>
                        <td>
                            <a class="layui-btn layui-btn-sm" href="${pageContext.request.contextPath}/items/editItems.action?id=${item.id}">修改</a>
                        </td>
                    </tr>
                </c:forEach>
                </tbody>
            </table>
        </div>
    </form>
</div>

<script>
    //渲染form表单
    layui.use('form', function () {
        var form = layui.form;
        form.render();
    });

    //要使用弹出层layer以及使用jquery的$要使用下面这种方式
    layui.use('layer',function(){
        var layer=layui.layer;
        var $=layui.$;

        // 在弹出层显示添加商品表单
        $("#add").on("click",function(){
            layer.open({
                title:'添加商品',
                type:2,     //表示通过url传入页面
                area:['600px','400px'],
                content:['${pageContext.request.contextPath}/items/addItems.action'],
                skin:'layui-layer-lan',
                btn:['添加','取消'],

                yes: function(index,layero){
                    // 获取iframe中的form表单元素
                    var formSubmit=window.parent.document.getElementById('layui-layer-iframe1').contentWindow.document.getElementById("formSubmit");
                    // 提交form表单
                    formSubmit.submit();
                    layer.msg('操作成功',{
                        icon:1,
                        time:3000
                    });
                    // 提交表单后关闭弹出层窗口
                    layer.close();
                    // 刷新页面
                    location.reload();
                }
            })
        });

        //批量删除商品
        $("#delete").on("click",function () {
            // 因为必须传回一个item_id数组才能执行删除操作,所以要判断是否有复选框被选中
            // 有复选框被选中时
            if($("input[type='checkbox']").is(":checked")){
                layer.alert('确定要删除吗',{
                    icon:3,
                    btn:['确定','取消'],
                    yes:function(){
                        // 修改form表单的提交路径
                        document.itemsForm.action="${pageContext.request.contextPath}/items/deleteItems.action";
                        document.itemsForm.submit();
                        layer.msg('删除成功',{icon:1});
                    }
                });
            }
            // 若没有复选框被选中
            else{
                layer.msg('请至少勾选一个商品',{
                    icon:0,
                    time:3000
                });
            }
        });

        // 进入批量修改页面
        $("#editQuery").on("click",function () {
            document.itemsForm.action="${pageContext.request.contextPath}/items/editQueryItems.action";
            document.itemsForm.submit();
        })
    })
</script>
</body>
</html>

批量修改的editQueryItems.jsp页面如下

<%--
  Created by IntelliJ IDEA.
  User: 光玉
  Date: 2018/4/3
  Time: 18:35
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<!DOCTYPE html>
<head>
    <title>批量修改商品</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script type="text/javascript" src="<%= request.getContextPath()%>/plugin/layui/layui.all.js"></script>
    <link rel="stylesheet" href="<%= request.getContextPath()%>/plugin/layui/css/layui.css">
</head>

<body>
<div style="margin-left: 250px">
    <form name="editItemsForm" class="layui-form" action="${pageContext.request.contextPath}/items/editQueryItems.action" method="post">
        <label class="layui-form-label">查询条件</label>
        <div class="layui-input-block">
            <label class="layui-form-label">商品名称</label>
            <div class="layui-input-inline">
                <input class="layui-input" type="text" name="itemCustom.name" placeholder="请输入关键字">
            </div>
            <div class="layui-input-inline">
                <button class="layui-btn" type="submit" id="find">查询</button>
            </div>
            <div class="layui-input-inline">
                <button class="layui-btn layui-btn-normal" type="button" id="editQuery">提交修改</button>
            </div>
        </div>

        <div style="width: 900px">
            <table class="layui-table" lay-size="sm">
                <thead>
                <th>商品名称</th>
                <th>商品价格</th>
                <th>商品详情</th>
                <th>生产日期</th>
                </thead>
                <tbody>
                <c:forEach items="${itemsList}" var="item" varStatus="status">
                    <tr>
                        <td class="layui-hide"><input type="text" name="itemsList[${status.index}].id" value="${item.id}"></td>
                        <td><input type="text" name="itemsList[${status.index}].name" value="${item.name}"/></td>
                        <td><input type="text" name="itemsList[${status.index}].price" value="${item.price}"/></td>
                        <td><input type="text" name="itemsList[${status.index}].detail" value="${item.detail}"/></td>
                        <td><input type="text" name="itemsList[${status.index}].createtime" value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/> "/></td>
						<td class="layui-hide"><input type="text" name="itemsList[${status.index}].pic" value="${item.pic}"/></td>
					</tr>
                </c:forEach>
                </tbody>
            </table>
        </div>
    </form>
</div>

<script>
    //渲染form表单
    layui.use('form', function () {
        var form = layui.form;
        form.render();
    });

    var $=layui.$;
    $("#editQuery").on("click",function () {
        document.editItemsForm.action="${pageContext.request.contextPath}/items/editQueryItemsSubmit.action";
        document.editItemsForm.submit();
    })
</script>
</body>
</html>

前端jsp中属性名和后台属性的对应关系:


整体运行结果如下:

添加商品:


批量删除商品(未选中复选框和选中时会弹出相应的提示信息)



批量修改商品

批量修改前页面


批量修改页面


批量修改后页面


绑定map类型

map类型的绑定和list绑定类似,也是需要在包装类中声明map
参考如下方式进行绑定:


异常处理

系统中的异常分为两类:

  • 预期处理异常
  • 运行时异常(RuntimeException)
    预期异常通过捕获异常来获取异常信息,让我们能根据异常信息来处理异常,
    而运行时异常则需要通过规范代码开发,测试等方式来减少其发生次数

1.异常处理的思路

在dao,service,controller层遇到异常时,都会向上抛出异常。这些异常
由springmvc DispatcherServlet前端控制器交给ExceptionResolver异常
处理器进行处理

注意:springmvc全局配置统一的异常处理器(一个系统只有一个异常处理器)

2.编写自定义异常类

在src目录下新建exception包,编写继承Exception的CustomException


package exception;

/**
 * 自定义异常类,用来将预期异常信息返回到程序中
 */
public class CustomException extends Exception{
    // 异常信息(有可能是预期异常或者运行时异常)
    // 需要在CustomExceptionResolver异常处理器判断
    public String message;

    public String CustomException(String message){
        // super(message);
        this.message=message;
    }

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

3.编写全局异常处理器

首先我们需要分析异常类型:
如果是系统自定义的异常,则直接取出错误信息,并在错误页面中显示
如果不是系统自定义异常,则需要构造一个自定义异常类型(抛出未知错误)
使用springmvc提供的HandlerExceptionResolver接口

在exception包下创建CustomExceptionResolver.java文件实现HandlerExceptionResolver接口


package exception;

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CustomExceptionResolver implements HandlerExceptionResolver{

    // 全局异常处理类
    // Exception e就是系统抛出的异常
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {

        CustomException customException=null;
        String message=null;
        ///如果是系统自定义异常,则直接取出异常
        if(e instanceof CustomException){
            customException=(CustomException)e;
        }
        else{   //否则抛出“未知错误”
            customException=new CustomException("未知错误55555");
        }
        message=customException.getMessage();

        //将错误信息传到显示错误信息的页面
        ModelAndView modelAndView=new ModelAndView();
        modelAndView.addObject("message",message);
        modelAndView.setViewName("errorPage");

        return modelAndView;
    }
}

在dao,controller,service层处抛出的异常都交给异常处理器处理

4.配置全局异常处理器

在springmvc.xml中配置全局异常处理器

<!-- 配置全局异常处理器
     由于实现了HandlerExceptionResolver,系统知道是全局异常处理器
      不需要设置id -->
 <bean class="exception.CustomExceptionResolver"/>

5.测试异常

如果是手动抛出异常,则在错误页面显示自定义异常信息,
如果不是手动抛出异常,说明是运行时错误(比如说:除0)
则在页面中显示“未知错误55555”

可以测试一下根据id查找修改的商品信息
将ItemsServiceImpl中的findItemsById改写一下

@Override
public ItemCustom findItemsById(Integer id) throws Exception{
    //通过mapper包下itemsMapper中的selectByPrimaryKey方法找到相应的item
    Items items=itemsMapper.selectByPrimaryKey(id);

    // 判断根据id找到的items对象是否为空
    // 若为空,则抛出下面的自定义异常
    if(items == null){
        throw new CustomException("修改商品信息错误,不存在对应商品!");
    }

    //考虑到可能扩展另外的属性,这里使用继承了Items类的ItemCustom类
    ItemCustom itemCustom=new ItemCustom();

    //通过spring提供的BeanUtils.copyProperties方法将items的属性拷贝到itemCustom中
    BeanUtils.copyProperties(items,itemCustom);
    return itemCustom;
}

在地址栏中输入http://localhost:8080/ssm-highclass/items/editItems.action?id=555
由于没有id为555的商品信息,系统发现异常后会提交给异常处理器处理
异常处理器会将错误信息显示到页面上
异常可以在service中抛出,也可以在controller中抛出,主要看是否与业务功能有关
与业务功能有关的在service抛出异常,否则在controller抛出异常

图片上传

1.设置上传图片的存储目录

企业一般都是通过服务器存放图片,这里使用的是intellij idea来设置图片存储目录
在tomcat的Deployment下引入External Source,只要是电脑上的一个文件夹就行,
配置路径为/img

输入http://localhost:8080/img/图片名称即可访问
图片尽量分级存放到相应目录中,提高访问速度

注意:需要在form中添加属性enctype=”multipart/form-data”
需要通过springmvc图片解析器解析

2.配置图片上传解析器

这里需要引入两个包:commons-fileupload-1.2.2.jar和依赖包commons-io-2.4.jar
然后在springmvc.xml中配置图片上传解析器


<!-- 配置图片上传解析器 -->
<!-- springmvc的multipartResolver图片解析器依赖于commons-fileupload.jar包 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize">
        <!-- 最大上传文件容量(字节为单位) -->
        <!-- 这里设置了最大为10Mb -->
        <value>10485760</value>
    </property>
</bean>

3.编写controller

在controller的editItemsSubmit方法下新增形参MultipartFile items_img

@RequestMapping("/editItemsSubmit")
public String editItemsSubmit(HttpServletRequest request, Integer id, ItemCustom itemCustom, MultipartFile items_img) throws Exception{
    //通过service返回修改后的页面
    //形参中传递了pojo类型参数(即itemCustom)

    // 如果图片不为空
    if(items_img!=null && items_img.getOriginalFilename()!=null && items_img.getOriginalFilename().length()>0){
        //图片上传物理路径
        String img_path="D:\\JavaWeb\\img\\";
        //获取图片原始名称
        String originalFilename=items_img.getOriginalFilename();

        //生成新的图片名称
        //为了避免文件名冲突,使用java的UUID随机生成字符串再加上原来图片后缀名构成新的名字
        String newFileName= UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
        //新图片
        File newFile=new File(img_path+newFileName);

        //将内存中的数据写入磁盘
        items_img.transferTo(newFile);
        //将新图片名称写到数据库中
        itemCustom.setPic(newFileName);

        System.out.println(newFileName);
    }
    // 更新数据库数据
    itemsService.updateItems(id,itemCustom);

    //重定向到商品查询列表
    return "forward:queryItems.action";
}

在editItems.jsp添加图片显示代码

 <div class="layui-form-item">
     <label class="layui-form-label">商品图片</label>
     <div class="layui-input-inline">
         <c:if test="${itemCustom.pic != null}">
             <%-- 取绝对路径 --%>
             <img src="/img/${itemCustom.pic}" width="100" height="100"/><br/>
         </c:if>
         <input type="file" name="items_img">
<%-- 不写上下面这一行的话就不能把已有的pic的值传回到后台中 --%>
         <input class="layui-hide" type="text" name="pic" value="${itemCustom.pic}"/>
     </div>
 </div>

效果如下:


json数据交互

json数据格式比较简单,易于阅读和编写,经常用于接口传输,html中ajax异步刷新等领域中。
使用json格式也比较容易进行解析。

1.springmvc进行json交互过程

首先,我们来了解一下springmvc进行json交互的过程。
客户端发起请求,有两种请求方式

  • 请求json串
    这种情况下需要使用@RequestBody注解将json串转换为java对象
    
  • 请求key/value
    不需要@RequestBody转换为java对象
    
    无论是json串还是key/value都要@ResponseBody将java对象转换为json串输出到客户端,
    方便客户端进行解析

2.准备环境

springmvc默认使用MappingJacksonHttpMessageConverter对json数据进行转换操作,
这里引入了fastjson-1.2.47.jar包来进行配置

3.配置springmvc的json转换器

我这里使用的是springmvc的注解驱动,需要在注解驱动中加入fastjson的配置


<!-- 这里使用注解驱动来进行配置,在注解驱动中加入fastjson的配置 -->
<mvc:annotation-driven conversion-service="conversionService">
    <mvc:message-converters register-defaults="true">
        <!-- 避免IE执行AJAX时,返回JSON出现下载文件 -->
        <bean id="fastJsonHttpMessageConverter" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
            <property name="supportedMediaTypes">
                <list>
                    <value>application/json;charset=UTF-8</value>
                </list>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

4.编写json转换控制器

package controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import po.ItemCustom;

/**
 * json交互的控制器
 */

@Controller
public class JsonTestController {

    /**
     *
     * @param itemCustom(@RequestBody 请求json)(商品信息)
     * @return itemCustom (@ResponseBody 返回json)(商品信息)
     */
    @RequestMapping(value="/requestJson",method = {RequestMethod.POST})
    public @ResponseBody ItemCustom requestJson(@RequestBody ItemCustom itemCustom) throws Exception{
        // 由于请求的是json串,需要使用@RequestBody将json串转换为java对象
        // 由于需要向客户端返回json数据,需要用@ResponseBody将java对象转换为json串
        return itemCustom;
    }


    @RequestMapping("/responseJson")
    public @ResponseBody ItemCustom responseJson(ItemCustom itemCustom) throws Exception{
        // 请求的是key/value,不需要@RequestBody
        // 使用@ResponseBody返回json数据
        return itemCustom;
    }
}

5.编写json测试的jsp文件

在web目录下新建jsonTest.jsp文件,注意不要把文件放到WEB-INF目录下

<%--
  Created by IntelliJ IDEA.
  User: 光玉
  Date: 2018/4/13
  Time: 11:37
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="utf-8" %>
<html>
<head>
    <title>json转换测试</title>
    <script type="text/javascript" src="<%= request.getContextPath()%>/plugin/layui/layui.all.js"></script>
    <link rel="stylesheet" href="<%= request.getContextPath()%>/plugin/layui/css/layui.css">
    <%--<script type="text/javascript" src="<%= request.getContextPath()%>/plugin/jquery/jquery.js"></script>--%>
</head>
<body>
    <button class="layui-btn" type="button" id="requestJson">请求json</button>
    <button class="layui-btn layui-btn-normal" type="button" id="responseJson">请求key/value</button>

    <script>
        var $=layui.$;

        // 请求是json串,返回的也是json串
        $("#requestJson").on("click",function () {
            $.ajax({
                type:'post',
                url:'${pageContext.request.contextPath}/requestJson.action',    //设置请求的url
                contentType:'application/json;charset=utf-8',   //将请求类型设置为json格式
                data:'{"name":"天堂伞", "price":"45"}',
                success:function (data) {   //返回json
                    alert(data.name);
                }
            })
        });

        //请求key/value,返回json串
        $("#responseJson").on("click",function () {
            // 请求是json串,返回的也是json串
            $.ajax({
                type:'post',
                url:'${pageContext.request.contextPath}/responseJson.action',    //设置请求的url
                // contentType:'application/json;charset=utf-8',   //默认即为传输key/value格式的数据,不需要设置
                data:'name=毕业花束&price=79',  //key/value类型数据
                success:function (data) {   //返回json
                    alert(data.name);
                }
            })
        })
    </script>
</body>
</html>

6.查看运行结果

在地址栏中输入http://localhost:8080/ssm-highclass/jsonTest.jsp,显示出两个按钮
“请求json“和”请求key/value“,分别点击,显示效果如下

request请求json的content-type格式以及json格式数据


request请求key/value的content-type格式以及key/value格式数据



可以看到,两种不同的请求方式,最终都返回json串

7.记录一下配置json踩过的坑

由于我使用的是spring4.x的版本,已经不能再使用Jackson1.x版本来进行配置。
还有就是,在网上看到使用spring4.x配置jackson2.5.0版本,也试着去配了一下,
还是不行。最终还是使用fastjson配置成功。

RESTful架构

1.了解RESTful

RESTful架构,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。若要了解更多概念,可以看看阮一峰的博客

2.使用RESTful

1.需求

使用RESTful方式实现根据id查看商品信息

2.配置前端控制器

之前配置的前端控制器url模式是”.action”,而RESTful方式url模式是”/“
根据RESTful方式配置前端控制器,即在web.xml中添加如下内容


<!-- RESTful前端控制器配置,可以和之前设置的.action前端控制器并存 -->
<servlet>
    <servlet-name>springmvcRESTful</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 加载springmvc配置文件 -->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <!-- 配置文件的地址,如果不配置contextConfigLocation,
             默认查找的配置文件名称是classpath下的:servlet名称+"-servlet.xml"即springmvc-servlet.xml-->
        <param-value>classpath:config/spring/springmvc.xml</param-value>
    </init-param>
</servlet>

<servlet-mapping>
    <servlet-name>springmvcRESTful</servlet-name>
    <!-- 可以配置/  表示此工程所有请求全部由springmvc解析,此方式可以实现RESTful(表征性状态转移,总结起来应该是是一种简洁的架构风格)方式,
                    静态文件不能由springmvc解析,需要特殊处理  -->
    <url-pattern>/</url-pattern>
</servlet-mapping>

3.编写controller

使用了url模板映射方式(结合下面的controller理解)

  • 请求参数映射到{id}
  • {id}传递到方法里面的@PathVariable(“id”)中
  • 通过@Pathvariable把{id}传递到方法里面的id

利用servlet拦截请求目录功能,实现无扩展名的restfull风格

// RESTful格式编写
// 根据id查询商品,输出为json串
// 使用/itemsView/{id}将"{}"里的参数传到@PathVariable指定的名称中
// 若有多个,如:/itemsView/{id}/{name} ,则在形参中再定义相同数量的@PathVariable
@RequestMapping("/itemsView/{id}")
public @ResponseBody ItemCustom itemsView(@PathVariable("id") Integer id) throws Exception{

    ItemCustom itemCustom=itemsService.findItemsById(id);
    return itemCustom;
}

4.查看运行结果

在浏览器地址栏中输入http://localhost:8080/ssm-highclass/items/itemsView/1
可以在页面中看到json格式的数据

但是,在配置了RESTful方式后,当我们要访问web过程中的静态资源时,
会发现访问不了。这是因为springmvc在设置了RESTful方式后会对静态资源
也进行拦截解析。因此,我们要在web.xml中设置静态资源解析方式
在web.xml中添加如下内容:

<!-- 当我们配置了RESTful方式访问时,静态资源(js,css,img...)也会经过springmvc进行解析
     要避免这种情况,就要对静态资源的解析进行配置 -->
<!-- 比如说web/plugin/jquery是放jquery插件的地方,里面包含jqery.js文件
     配置后凡是“/plugin/jquery/”下的请求,都会在过程目录下的“/plugin/jquery/”下找相应文件 -->
<mvc:resources mapping="/plugin/jquery/**" location="/plugin/jquery/"/>

拦截器

用户请求到DispatherServlet中,DispatherServlet调用HandlerMapping查找Handler,HandlerMapping返回一个拦截的链儿(多个拦截),springmvc中的拦截器是通过HandlerMapping来进行拦截的

拦截器通常用于用户认证(登录信息认证之类的),权限认证等方面

1.设置springmvc拦截器方法

在controller包下新建interceptor包,在interceptor包下新建HandlerInterceptorTest1.java继承HandlerInterceptor接口

package controller.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HandlerInterceptorTest1 implements HandlerInterceptor{
    // 重写HandlerInterceptor里的三个方法

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        // preHanle方法是在进入handler之前进行拦截
        // 通常用于用户登录认证拦截,用户权限拦截

        System.out.println("HandlerInterceptorTest1....preHandle");

        //返回false表示进行拦截,true则表示不拦截,继续执行handler
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        // postHandle方法是在进入handler之后,返回ModelAndView之前进行拦截
        // 可以在这里边放置一些公共的数据或视图资源

        System.out.println("HandlerInterceptorTest1....postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        // afterCompletion方法在执行完handler之后执行
        // 做系统统一异常处理,进行方法执行性能监控,在prehandler中设置一个时间点,在afterCompletion设置一个时间点,两个时间点的差就是执行时长
        // 实现系统统一日志记录

        System.out.println("HandlerInterceptorTest1....afterCompletion");
    }
}

再编写一个HandlerInterceptorTest2.java继承HandlerInterceptor接口

package controller.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class HandlerInterceptorTest2 implements HandlerInterceptor{
    // 重写HandlerInterceptor里的三个方法

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        // preHanle方法是在进入handler之前进行拦截
        // 通常用于用户登录认证拦截,用户权限拦截

        System.out.println("HandlerInterceptorTest2....preHandle");

        //返回false表示进行拦截,true则表示不拦截,继续执行handler
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        // postHandle方法是在进入handler之后,返回ModelAndView之前进行拦截
        // 可以在这里边放置一些公共的数据或视图资源

        System.out.println("HandlerInterceptorTest2....postHandle");
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        // afterCompletion方法在执行完handler之后执行
        // 做系统统一异常处理,进行方法执行性能监控,在prehandler中设置一个时间点,在afterCompletion设置一个时间点,两个时间点的差就是执行时长
        // 实现系统统一日志记录

        System.out.println("HandlerInterceptorTest2....afterCompletion");
    }
}

2.全局配置拦截器

在springmvc中添加如下内容:

<!-- 配置全局拦截器 -->
<mvc:interceptors>
    <!-- 配置拦截器1 -->
    <mvc:interceptor>
        <!-- 这里的“/**”表示所有url请求都进行拦截 -->
        <mvc:mapping path="/**"/>
        <bean class="controller.interceptor.HandlerInterceptorTest1"/>
    </mvc:interceptor>
    <!-- 配置拦截器2 -->
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="controller.interceptor.HandlerInterceptorTest2"/>
    </mvc:interceptor>
</mvc:interceptors>

3.测试拦截器

拦截器1和2都放行,测试结果为:

HandlerInterceptor1...preHandle
HandlerInterceptor2...preHandle

HandlerInterceptor2...postHandle
HandlerInterceptor1...postHandle

HandlerInterceptor2...afterCompletion
HandlerInterceptor1...afterCompletion

即preHandle顺序执行,postHandle和afterCompletion倒序执行

拦截器1放行,2拦截(界面显示是空白的,不会出现错误信息,在控制台中查看)

HandlerInterceptor1...preHandle
HandlerInterceptor2...preHandle
HandlerInterceptor1...afterCompletion

可以看出如果preHandle不放行,postHandle、afterCompletion都不执行。只要有一个拦截器不放行,controller不能执行完成。

拦截器1和2都进行拦截,结果为

HandlerInterceptor1...preHandle

说明了只有在前边的拦截器放行后,后边的preHandle方法才会执行

模拟登陆认证

现在的用户登录认证,权限认证大多都通过shiro来实现。由于现在对shiro还不太了解,这里便通过对session的操作,来模拟登陆认证过程

1.编写LoginController控制器

通过LoginController控制器来进行session的管理
在controller包下新建LoginController.java

package controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpSession;

@Controller
public class LoginController {

    // 登录
    @RequestMapping("/login")
    public String login(HttpSession httpSession,String username,String password){
        // 通过前台登录,将username保存到session中
        httpSession.setAttribute("username",username);
        
		// 重定向到商品查询页面
        return "redirect:items/queryItems.action";
    }

    // 退出
    @RequestMapping("/logout")
    public String logout(HttpSession httpSession){
        // 让session过期,清除里面保存的username信息
        httpSession.invalidate();

        // 重定向回商品查询页面
        return "redirect:login.action";
    }
}

2.编写登录页面

我们需要一个登录页面来进行登录认证

<%--
  Created by IntelliJ IDEA.
  User: 光玉
  Date: 2018/4/14
  Time: 22:40
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>

<!DOCTYPE html>
<html>
<head>
    <title>登录认证</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script type="application/x-javascript"> addEventListener("load", function() { setTimeout(hideURLbar, 0); }, false); function hideURLbar(){ window.scrollTo(0,1); } </script>
    <meta name="keywords" content="Login" />
    <link href="${pageContext.request.contextPath}/assets/css/style.css" rel='stylesheet' type='text/css' />
    <!--webfonts-->
    <link href='http://fonts.useso.com/css?family=PT+Sans:400,700,400italic,700italic|Oswald:400,300,700' rel='stylesheet' type='text/css'>
    <link href='http://fonts.useso.com/css?family=Exo+2' rel='stylesheet' type='text/css'>
    <!--//webfonts-->
    <%--<script src="http://ajax.useso.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>--%>
    <script src="${pageContext.request.contextPath}/plugin/jquery/jquery.js"></script>
</head>
<body>
<script>$(document).ready(function(c) {
    $('.close').on('click', function(c){
        $('.login-form').fadeOut('slow', function(c){
            $('.login-form').remove();
        });
    });
});
</script>
<!--SIGN UP-->
<h1>Login</h1>
<div class="login-form">
    <div class="close"> </div>
    <div class="head-info">
        <label class="lbl-1"> </label>
        <label class="lbl-2"> </label>
        <label class="lbl-3"> </label>
    </div>
    <div class="clear"> </div>
    <div class="avtar">
        <img src="${pageContext.request.contextPath}/assets/images/avtar.png" />
    </div>
    <form action="${pageContext.request.contextPath}/login.action" method="post">
        <input type="text" class="text" name="username" value="username" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'username';}" >
        <div class="key">
            <input type="password" name="password" value="password" onfocus="this.value = '';" onblur="if (this.value == '') {this.value = 'password';}">
        </div>
        <div class="signin">
            <input type="submit" value="Login" >
        </div>
    </form>
</div>
<div class="copy-rights">
    <p>Copyright &copy; 2018.光玉</p>
</div>

</body>
</html>

登录页面所需的静态资源保存在/web/assets下,由于之前设置了RESTful模式,会对静态资源也进行解析,这里需要在springmvc中进行配置

<!-- 在之前配置静态资源的地方添加一下内容 -->
<mvc:resources mapping="/assets/**" location="/assets/"/>

3.在商品查询页面显示用户名

为商品查询页面添加顶部导航栏显示,在用户登录时显示相应的登录名,没有登录时在右上角显示“请登录”。修改后的itemsList.jsp内容如下

<%--
  Created by IntelliJ IDEA.
  User: 光玉
  Date: 2018/4/3
  Time: 18:35
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<!DOCTYPE html>
<head>
    <title>查询商品列表</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <script type="text/javascript" src="<%= request.getContextPath()%>/plugin/layui/layui.all.js"></script>
    <link rel="stylesheet" href="<%= request.getContextPath()%>/plugin/layui/css/layui.css">
</head>

<!-- 这下面是修改的部分 -->

<body class="layui-layout-body">
<!-- 顶部导航栏 -->
<div class="layui-layout layui-layout-admin">
    <div class="layui-header">
        <div class="layui-logo">商品管理后台</div>
        <ul class="layui-nav layui-layout-right">
            <!-- 判断在session中是否保存着username,若存在,则显示出用户名
                 否则,显示“请登录” -->
            <c:if test="${username != null}">
                <li class="layui-nav-item">
                    <a href="javascript:;">
                        <img src="http://t.cn/RCzsdCq" class="layui-nav-img">
                        ${username}
                    </a>
                </li>
                <li class="layui-nav-item">
                    <a href="${pageContext.request.contextPath}/logout.action">退了</a>
                </li>
            </c:if>
            <c:if test="${username == null}">
                <li class="layui-nav-item">
                    <a href="${pageContext.request.contextPath}/login.jsp">请登录</a>
                </li>
            </c:if>
        </ul>
    </div>
</div>
<div style="margin-left: 250px;margin-top:60px">

<!-- 这上面是修改的部分 -->
    <form name="itemsForm" class="layui-form" action="${pageContext.request.contextPath}/items/queryItems.action" method="post">
        <label class="layui-form-label">查询条件</label>
        <div class="layui-input-block">
            <label class="layui-form-label">商品名称</label>
            <div class="layui-input-inline">
                <input class="layui-input" type="text" name="itemCustom.name" placeholder="请输入关键字">
            </div>
            <div class="layui-input-inline">
                <button class="layui-btn" type="submit" id="find">查询</button>
            </div>
            <div class="layui-input-inline">
                <button class="layui-btn layui-btn-normal" type="button" id="add">添加商品</button>
            </div>
            <div class="layui-input-inline">
                <button class="layui-btn layui-btn-danger" type="button" id="delete">批量删除</button>
            </div>
            <div class="layui-input-inline">
                <button class="layui-btn layui-btn-normal" type="button" id="editQuery">批量修改</button>
            </div>
        </div>

        <div style="width: 900px">
            <table class="layui-table" lay-size="sm">
                <thead>
                <th>批量删除</th>
                <th>商品名称</th>
                <th>商品价格</th>
                <th>商品详情</th>
                <th>生产日期</th>
                <th>操作</th>
                </thead>
                <tbody>
                <c:forEach items="${itemsList}" var="item">
                    <tr>
                        <td><input type="checkbox" name="item_id" value="${item.id}"/> </td>
                        <td>${item.name}</td>
                        <td>${item.price}</td>
                        <td>${item.detail}</td>
                        <td><fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/> </td>
                        <td>
                            <a class="layui-btn layui-btn-sm" href="${pageContext.request.contextPath}/items/editItems.action?id=${item.id}">修改</a>
                        </td>
                    </tr>
                </c:forEach>
                </tbody>
            </table>
        </div>
    </form>
</div>

<script>
    //渲染form表单
    layui.use('form', function () {
        var form = layui.form;
        form.render();
    });

    //要使用弹出层layer以及使用jquery的$要使用下面这种方式
    layui.use('layer',function(){
        var layer=layui.layer;
        var $=layui.$;

        // 在弹出层显示添加商品表单
        $("#add").on("click",function(){
            layer.open({
                title:'添加商品',
                type:2,     //表示通过url传入页面
                area:['600px','400px'],
                content:['${pageContext.request.contextPath}/items/addItems.action'],
                skin:'layui-layer-lan',
                btn:['添加','取消'],

                yes: function(index,layero){
                    // 获取iframe中的form表单元素
                    var formSubmit=window.parent.document.getElementById('layui-layer-iframe1').contentWindow.document.getElementById("formSubmit");
                    // 提交form表单
                    formSubmit.submit();
                    layer.msg('操作成功',{
                        icon:1,
                        time:3000
                    });
                    // 提交表单后关闭弹出层窗口
                    layer.close();
                    // 刷新页面
                    location.reload();
                }
            })
        });

        //批量删除商品
        $("#delete").on("click",function () {
            // 因为必须传回一个item_id数组才能执行删除操作,所以要判断是否有复选框被选中
            // 有复选框被选中时
            if($("input[type='checkbox']").is(":checked")){
                layer.alert('确定要删除吗',{
                    icon:3,
                    btn:['确定','取消'],
                    yes:function(){
                        // 修改form表单的提交路径
                        document.itemsForm.action="${pageContext.request.contextPath}/items/deleteItems.action";
                        document.itemsForm.submit();
                        layer.msg('删除成功',{icon:1});
                    }
                });
            }
            // 若没有复选框被选中
            else{
                layer.msg('请至少勾选一个商品',{
                    icon:0,
                    time:3000
                });
            }
        });

        // 进入批量修改页面
        $("#editQuery").on("click",function () {
            document.itemsForm.action="${pageContext.request.contextPath}/items/editQueryItems.action";
            document.itemsForm.submit();
        })
    })
</script>
</body>
</html>

4.运行结果

由于之前设置了设置了拦截器,在运行之前要先把springmvc.xml设置的拦截器注释掉
即注释掉这一部分

<!-- 配置全局拦截器 -->
<!--<mvc:interceptors>-->
    <!--<!– 拦截器的执行顺序会按照配置的顺序执行 –>-->
    <!--<!– 配置拦截器1 –>-->
    <!--<mvc:interceptor>-->
        <!--<!– 这里的“/**”表示所有url请求都进行拦截 –>-->
        <!--<mvc:mapping path="/**"/>-->
        <!--<bean class="controller.interceptor.HandlerInterceptorTest1"/>-->
    <!--</mvc:interceptor>-->
    <!--<!– 配置拦截器2 –>-->
    <!--<mvc:interceptor>-->
        <!--<mvc:mapping path="/**"/>-->
        <!--<bean class="controller.interceptor.HandlerInterceptorTest2"/>-->
    <!--</mvc:interceptor>-->
<!--</mvc:interceptors>-->

登录页面:



输入用户名后进行登录,用户名显示在右上角


点击右上角的“退出”后,用户信息会被注销



若需要项目源码,可以到 我的github项目:ssm-highclass 下载






猜你喜欢

转载自blog.csdn.net/silversoldier/article/details/80337384