SpringMVC实战crud增删改查

一.公共页面的跳转

1.编写页面跳转控制类

java 复制代码
package com.YU.web;

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

/**
 * @author YU
 * @create 2023-09-07 14:41
 */
@Controller
public class PageController {

    @RequestMapping("/page/{page}")
    public String toPage(@PathVariable("page") String page){
        return page;
    }

    @RequestMapping("/page/{dir}{page}")
    public String toDirPage(
            @PathVariable("dir") String dir,
            @PathVariable("page") String page){
        return dir + "/" + page;
    }
}

二.后端实现crud

1.利用mybatis插件生成实体模型和mapper接口和xml文件

在生成后的HBookMapper接口中,需要加上@Repository给Spring进行托管

2.编写切面类和工具类

2.1切面类:

java 复制代码
package com.YU.aspect;

import com.YU.utils.PageBean;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * @author YU
 * @create 2023-08-25 17:17
 */
@Aspect //代表当前类为切面类
@Component //代表当前类交给Spring进行管理
public class PagerAspect {
    @Around("execution(* *..*biz.*Pager(..))")
    public Object invoke(ProceedingJoinPoint args) throws Throwable {
        PageBean pageBean = null;
        //获取目标方法的所有参数
        Object[] ars = args.getArgs();
        for (Object param : ars) {
            if(param instanceof PageBean){
                pageBean = (PageBean)param;
                break;
            }
        }

        if(pageBean != null && pageBean.isPagination())
            PageHelper.startPage(pageBean.getPage(),pageBean.getRows());

        Object list = args.proceed();

        if(null != pageBean && pageBean.isPagination()){
            PageInfo pageInfo = new PageInfo((List) list);
            pageBean.setTotal((int) pageInfo.getTotal());
        }
        return list;
    }

}

2.2 工具类

java 复制代码
package com.YU.utils;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.Map;

public class PageBean implements Serializable {

	private static final long serialVersionUID = 2422581023658455731L;

	//页码
	private int page=1;
	//每页显示记录数
	private int rows=10;
	//总记录数
	private int total=0;
	//是否分页
	private boolean isPagination=true;
	//上一次的请求路径
	private String url;
	//获取所有的请求参数
	private Map<String,String[]> map;
	
	public PageBean() {
		super();
	}
	
	//设置请求参数
	public void setRequest(HttpServletRequest req) {
		String page=req.getParameter("page");
		String rows=req.getParameter("rows");
		String pagination=req.getParameter("pagination");
		this.setPage(page);
		this.setRows(rows);
		this.setPagination(pagination);
		this.url=req.getContextPath()+req.getServletPath();
		this.map=req.getParameterMap();
	}
	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public Map<String, String[]> getMap() {
		return map;
	}

	public void setMap(Map<String, String[]> map) {
		this.map = map;
	}

	public int getPage() {
		return page;
	}

	public void setPage(int page) {
		this.page = page;
	}
	
	public void setPage(String page) {
		if(null!=page&&!"".equals(page.trim()))
			this.page = Integer.parseInt(page);
	}

	public int getRows() {
		return rows;
	}

	public void setRows(int rows) {
		this.rows = rows;
	}
	
	public void setRows(String rows) {
		if(null!=rows&&!"".equals(rows.trim()))
			this.rows = Integer.parseInt(rows);
	}

	public int getTotal() {
		return total;
	}

	public void setTotal(int total) {
		this.total = total;
	}
	
	public void setTotal(String total) {
		this.total = Integer.parseInt(total);
	}

	public boolean isPagination() {
		return isPagination;
	}
	
	public void setPagination(boolean isPagination) {
		this.isPagination = isPagination;
	}
	
	public void setPagination(String isPagination) {
		if(null!=isPagination&&!"".equals(isPagination.trim()))
			this.isPagination = Boolean.parseBoolean(isPagination);
	}
	
	/**
	 * 获取分页起始标记位置
	 * @return
	 */
	public int getStartIndex() {
		//(当前页码-1)*显示记录数
		return (this.getPage()-1)*this.rows;
	}
	
	/**
	 * 末页
	 * @return
	 */
	public int getMaxPage() {
		int totalpage=this.total/this.rows;
		if(this.total%this.rows!=0)
			totalpage++;
		return totalpage;
	}
	
	/**
	 * 下一页
	 * @return
	 */
	public int getNextPage() {
		int nextPage=this.page+1;
		if(this.page>=this.getMaxPage())
			nextPage=this.getMaxPage();
		return nextPage;
	}
	
	/**
	 * 上一页
	 * @return
	 */
	public int getPreivousPage() {
		int previousPage=this.page-1;
		if(previousPage<1)
			previousPage=1;
		return previousPage;
	}

	@Override
	public String toString() {
		return "PageBean [page=" + page + ", rows=" + rows + ", total=" + total + ", isPagination=" + isPagination
				+ "]";
	}
}

3.编写biz层

java 复制代码
package com.YU.biz;

import com.YU.model.HBook;
import com.YU.utils.PageBean;

import java.util.List;

public interface HBookbiz {
    int deleteByPrimaryKey(Integer bid);

    int insert(HBook record);

    int insertSelective(HBook record);

    HBook selectByPrimaryKey(Integer bid);

    int updateByPrimaryKeySelective(HBook record);

    int updateByPrimaryKey(HBook record);

    List<HBook> listPager(HBook hBook, PageBean pageBean);
}

注:

这个方法为查询返回列表方法,包含分页,因为切面类对其进行切面,所以在命名时,必须以Pager结尾

4.配置mapper.xml

XML 复制代码
<select id="selectBycon" resultType="com.YU.model.HBook" parameterType="com.YU.model.HBook" >
    select
    <include refid="Base_Column_List" />
    from t_mvc_book
    <where>
        <if test="bname != null">
            and bname like concat('%',#{bname},'%')
        </if>
    </where>
  </select>

5.编写相应的接口类(HBookMapper)

java 复制代码
    List<HBook> selectBycon(HBook hBook);

6.处理controller层发送到biz的请求(配置spring-mvc.xml)

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
      http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!--1) 扫描com.YU.web及子子孙孙包下的控制器(扫描范围过大,耗时)-->
    <context:component-scan base-package="com.YU"/>

    <!--2) 此标签默认注册DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter -->
    <mvc:annotation-driven />

    <!--3) 创建ViewResolver视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- viewClass需要在pom中引入两个包:standard.jar and jstl.jar -->
        <property name="viewClass"
                  value="org.springframework.web.servlet.view.JstlView"></property>
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!--4) 单独处理图片、样式、js等资源 -->
    <!-- <mvc:resources location="/css/" mapping="/css/**"/>
     <mvc:resources location="/js/" mapping="/js/**"/>
     <mvc:resources location="WEB-INF/images/" mapping="/images/**"/>-->
    <!--处理controller层发送请求到biz,会经过切面的拦截处理-->
    <aop:aspectj-autoproxy/>
</beans>

7.编写tag助手标签类

java 复制代码
package com.YU.tag;

import java.io.IOException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyTagSupport;

import com.YU.utils.PageBean;

public class PageTag extends BodyTagSupport{
	private PageBean pageBean;// 包含了所有分页相关的元素
	
	public PageBean getPageBean() {
		return pageBean;
	}

	public void setPageBean(PageBean pageBean) {
		this.pageBean = pageBean;
	}

	@Override
	public int doStartTag() throws JspException {
//		没有标签体,要输出内容
		JspWriter out = pageContext.getOut();
		try {
			out.print(toHTML());
		} catch (IOException e) {
			e.printStackTrace();
		}
		return super.doStartTag();
	}

	private String toHTML() {
		StringBuffer sb = new StringBuffer();
//		隐藏的form表单---这个就是上一次请求下次重新发的奥义所在
//		上一次请求的URL
		sb.append("<form action='"+pageBean.getUrl()+"' id='pageBeanForm' method='post'>");
		sb.append("	<input type='hidden' name='page'>");
//		上一次请求的参数
		Map<String, String[]> paramMap = pageBean.getMap();
		if(paramMap != null && paramMap.size() > 0) {
			Set<Entry<String, String[]>> entrySet = paramMap.entrySet();
			for (Entry<String, String[]> entry : entrySet) {
//				参数名
				String key = entry.getKey();
//				参数值
				for (String value : entry.getValue()) {
//					上一次请求的参数,再一次组装成了新的Form表单
//					注意:page参数每次都会提交,我们需要避免
					if(!"page".equals(key)) {
						sb.append("	<input type='hidden' name='"+key+"' value='"+value+"' >");
					}
				}
			}
		}
		sb.append("</form>");
		
//		分页条
		sb.append("<ul class='pagination justify-content-center'>");
		sb.append("	<li class='page-item "+(pageBean.getPage() == 1 ? "disabled" : "")+"'><a class='page-link'");
		sb.append("	href='javascript:gotoPage(1)'>首页</a></li>");
		sb.append("	<li class='page-item "+(pageBean.getPage() == 1 ? "disabled" : "")+"'><a class='page-link'");
		sb.append("	href='javascript:gotoPage("+pageBean.getPreivousPage()+")'>&lt;</a></li>");// less than 小于号
//		sb.append("	<li class='page-item'><a class='page-link' href='#'>1</a></li>");
//		sb.append("	<li class='page-item'><a class='page-link' href='#'>2</a></li>");
		sb.append("	<li class='page-item active'><a class='page-link' href='#'>"+pageBean.getPage()+"</a></li>");
		sb.append("	<li class='page-item "+(pageBean.getPage() == pageBean.getMaxPage() ? "disabled" : "")+"'><a class='page-link' href='javascript:gotoPage("+pageBean.nextPage()+")'>&gt;</a></li>");
		sb.append("	<li class='page-item "+(pageBean.getPage() == pageBean.getMaxPage() ? "disabled" : "")+"'><a class='page-link' href='javascript:gotoPage("+pageBean.maxPage()+")'>尾页</a></li>");
		sb.append("	<li class='page-item go-input'><b>到第</b><input class='page-link'");
		sb.append("	type='text' id='skipPage' name='' /><b>页</b></li>");
		sb.append("	<li class='page-item go'><a class='page-link'");
		sb.append("	href='javascript:skipPage()'>确定</a></li>");
		sb.append("	<li class='page-item'><b>共"+pageBean.getTotal()+"条</b></li>");
		sb.append("</ul>");
		
//		分页执行的JS代码
		sb.append("<script type='text/javascript'>");
		sb.append("	function gotoPage(page) {");
		sb.append("		document.getElementById('pageBeanForm').page.value = page;");
		sb.append("		document.getElementById('pageBeanForm').submit();");
		sb.append("	}");
		sb.append("	function skipPage() {");
		sb.append("		var page = document.getElementById('skipPage').value;");
		sb.append("		if (!page || isNaN(page) || parseInt(page) < 1 || parseInt(page) > "+pageBean.getMaxPage()+") {");
		sb.append("			alert('请输入1~"+pageBean.getMaxPage()+"的数字');");
		sb.append("			return;");
		sb.append("		}");
		sb.append("		gotoPage(page);");
		sb.append("	}");
		sb.append("</script>");
		
		return sb.toString();
	}
}

8.引入tld标签库

XML 复制代码
<?xml version="1.0" encoding="UTF-8" ?>

<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
    version="2.0">
    
  <description>YU 1.1 core library</description>
  <display-name>YU core</display-name>
  <tlib-version>1.1</tlib-version>
  <short-name>YU</short-name>
  <uri>http://jsp.veryedu.cn</uri>
  
  
  <tag>
    <name>page</name>
    <tag-class>com.YU.tag.PageTag</tag-class>
    <body-content>JSP</body-content>
    <attribute>
        <name>pageBean</name>
        <required>true</required>
        <rtexprvalue>true</rtexprvalue>
    </attribute>
  </tag>
  
</taglib>

9.编写controller类

java 复制代码
package com.YU.web;

import com.YU.biz.HBookbiz;
import com.YU.model.HBook;
import com.YU.utils.PageBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * @author YU
 * @create 2023-09-07 16:07
 */
@Controller
@RequestMapping("book")
public class HbookController {

    @Autowired
    private HBookbiz hBookbiz;

    //增加
    @RequestMapping("/add")
    public String add(HBook hBook){
         hBookbiz.insertSelective(hBook);
        return "redirect:/book/list";
    }
    //删除
    @RequestMapping("/del/{bid}")
    public String del(@PathVariable("bid")Integer bid){
        hBookbiz.deleteByPrimaryKey(bid);
        return "redirect:/book/list";
    }
    //修改
    @RequestMapping("/edit")
    public String edit(HBook hBook){
        hBookbiz.updateByPrimaryKeySelective(hBook);
        return "redirect:list";
    }
    //查询
    @RequestMapping("/list")
    public String list(HBook hBook, HttpServletRequest request){
//        hbook用来接收前台传递后台的参数
        PageBean pageBean = new PageBean();
        pageBean.setRequest(request);
        List<HBook> hBooks = hBookbiz.listPager(hBook, pageBean);
        request.setAttribute("lst",hBooks);
        request.setAttribute("pageBean",pageBean);
        return "book/list";
    }
    //数据回显
    @RequestMapping("/preSave")
    public String preSave(HBook hBook, Model model){
        if(hBook !=null && hBook.getBid()!=null && hBook.getBid()!=0){
            HBook b = hBookbiz.selectByPrimaryKey(hBook.getBid());
            model.addAttribute("b",b);
        }
        return "book/edit";
    }
}

10.编写前端页面

1.主页面(展示数据进行操作)

html 复制代码
<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<%@ taglib uri="http://jsp.veryedu.cn" prefix="z"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <link
            href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.css"
            rel="stylesheet">
    <script
            src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.5.0/js/bootstrap.js"></script>
    <title>博客列表</title>
    <style type="text/css">
        .page-item input {
            padding: 0;
            width: 40px;
            height: 100%;
            text-align: center;
            margin: 0 6px;
        }

        .page-item input, .page-item b {
            line-height: 38px;
            float: left;
            font-weight: 400;
        }

        .page-item.go-input {
            margin: 0 10px;
        }
    </style>
</head>
<body>
<form class="form-inline"
      action="${pageContext.request.contextPath }/book/list" method="get">
    <div class="form-group mb-2">
        <input type="text" class="form-control-plaintext" name="cname"
               placeholder="请输入班级名称">
        <!-- 			<input name="rows" value="20" type="hidden"> -->
        <!-- 不想分页 -->
        <%--        <input name="pagination" value="false" type="hidden">--%>
    </div>
    <button type="submit" class="btn btn-primary mb-2">查询</button>
    <a class="btn btn-primary mb-2" href="${pageContext.request.contextPath }/book/preSave">新增</a>
</form>

<table class="table table-striped">
    <thead>
    <tr>
        <th scope="col">书籍ID</th>
        <th scope="col">书籍名称</th>
        <th scope="col">书籍价格</th>
<%--        <th scope="col">班级图片</th>--%>
        <th scope="col">操作</th>
    </tr>
    </thead>
    <tbody>
    <c:forEach  var="b" items="${lst }">
        <tr>
            <td>${b.bid }</td>
            <td>${b.bname }</td>
            <td>${b.price }</td>
            <td>
                <a href="${pageContext.request.contextPath }/book/preSave?bid=${b.bid}">修改</a>
                <a href="${pageContext.request.contextPath }/book/del/${b.bid}">删除</a>
            </td>
        </tr>
    </c:forEach>
    </tbody>
</table>
<!-- 这一行代码就相当于前面分页需求前端的几十行了 -->
<z:page pageBean="${pageBean }"></z:page>
${pageBean }
</body>
</html>

2.增加修改界面(操作数据)

html 复制代码
<body>
<form action="${pageContext.request.contextPath }/${empty b ? 'book/add' : 'book/edit'}" method="post">
    cid:<input type="text" name="bid" value="${b.bid }"><br>
    bname:<input type="text" name="bname" value="${b.bname }"><br>
    price:<input type="text" name="price" value="${b.price }"><br>
    <input type="submit">
</form>
</body>

3.测试结果

感谢各位大大的收看,各位的支持和三连是博主更新的动力,感谢谢谢谢!!!!

相关推荐
皮皮林5514 分钟前
告别 OOM:EasyExcel 百万数据导出最佳实践(附开箱即用增强工具类)
java
..过云雨38 分钟前
17-2.【Linux系统编程】线程同步详解 - 条件变量的理解及应用
linux·c++·人工智能·后端
Da Da 泓39 分钟前
多线程(七)【线程池】
java·开发语言·线程池·多线程
To Be Clean Coder1 小时前
【Spring源码】getBean源码实战(三)
java·mysql·spring
Wokoo71 小时前
开发者AI大模型学习与接入指南
java·人工智能·学习·架构
BullSmall1 小时前
支持离线配置修改及删除操作的实现方案
前端
南山乐只1 小时前
【Spring AI 开发指南】ChatClient 基础、原理与实战案例
人工智能·后端·spring ai
全栈前端老曹1 小时前
【前端路由】Vue Router 嵌套路由 - 配置父子级路由、命名视图、动态路径匹配
前端·javascript·vue.js·node.js·ecmascript·vue-router·前端路由
电摇小人2 小时前
我的“C++之旅”(博客之星主题作文)
java·开发语言
资生算法程序员_畅想家_剑魔2 小时前
Java常见技术分享-23-多线程安全-总结
java·开发语言