Java+Servlet+Jsp(el, jstl)+MyBatis的CRUD练习小项目

2023-11-12

1 概述

这篇博客主要是分享一个基于Servlet+Jsp(el, jstl)+MyBatis的CRUD练习小项目。包括项目的源码,以及项目的逻辑。通过这个项目能够学习Java web中最基础的servlet,jsp和mybatis的使用,为后续Spring的学习打下基础。项目源代码
关键词:javaweb基础,servlet,jsp,mybatis;

2 系统展示

在这里插入图片描述
(图片要是看不清可以右键新标签打开)

3 功能实现

基本的增删改查功能,项目采样web层、service层和dao层,三层架构。每个功能的实现都是从dao层开始,然后是web层,最后才是service层。

3.1 环境准备

  1. 创建web项目,导入依赖。(使用idea创建项目可以看我的这篇博客:IDEA创建Maven web项目以及Tomcat部署项目的方法
  2. 创建三层架构的包,web,service,dao
  3. 创建数据库表tb_brand
  4. 创建pojo类,Brand类
  5. 配置MyBatis的基础环境,主要三步:配置MyBatis-config.xml,SQL的映射文件BrandMapper.xml(本项目中的sql语句比较简单,用的是注解开发),创建BrandMapper接口。

3.2 查询-查询所有记录

逻辑:通过点击“查询所有”跳转到SelectAllServlet,然后调用service,service会调用mapper。
在这里插入图片描述
首先创建mapper接口,并编写selectAll()。

    @Select("select * from tb_brand")
    @ResultMap("brandResultMap")
    List<Brand> selectAll();

因为是简单的sql语句,所以使用注解开发。注意,select返回的数据库的字段与pojo的属性名并不一致,所以通过在BrandMapper.xml中的resultMap进行映射。

    <resultMap id="brandResultMap" type="Brand">
        <result column="brand_name" property="brandName"/>
        <result column="company_name" property="companyName"/>
    </resultMap>

column表示数据库中的字段,property表示brand类的属性名。
完成Dao层后,编写service层,创建一个BrandService类,添加一个selectAll()。

    public List<Brand> selectAll(){


        SqlSession sqlSession = sqlSessionFactory.openSession();

        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);

        List<Brand> brands = mapper.selectAll();

        sqlSession.close();

        return brands;
    }

这里使用了SqlSessionFactory工厂创建sqlSession,工厂只需要创建一次并且每个service方法中都要使用工厂,所以将这部分功能抽象成一个工具类SqlSessionFactoryUtils

public class SqlSessionFactoryUtils {

    private static SqlSessionFactory sqlSessionFactory;
    static {
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }
    public static SqlSessionFactory getSqlSessionFactory(){return sqlSessionFactory;}

service层完成后,先编写前端的jsp页面(brand.jsp)。在这里只展示关键部分。通过jstl的<c:forEach>标签从servlet中读取selectAll()方法的返回结果,并遍历出来。

    <c:forEach items="${brands}" var="brand" varStatus="status">
        <tr align="center">
                <%--      <td>${brand.id}</td>--%>
            <td>${status.count}</td>
            <td>${brand.brandName}</td>
            <td>${brand.companyName}</td>
            <td>${brand.ordered}</td>
            <td>${brand.description}</td>

            <c:if test="${brand.status == 1}">
                <td>启用</td>
            </c:if>
            <c:if test="${brand.status == 0}">
                <td>禁用</td>
            </c:if>
            <td><a href="#">修改</a> <a href="#">删除</a></td>
        </tr>
    </c:forEach>

最后实现servlet

@WebServlet("/selectAllServlet")
public class SelectAllServlet extends HttpServlet {
    
    private BrandService service = new BrandService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 调用service的selectAll()
        List<Brand> brands = service.selectAll();
        // 将查询结果封装值req
        req.setAttribute("brands", brands);
        // 将req请求转发至brand.jsp,brand.jsp就能通过el表达式从req中读取数据
        req.getRequestDispatcher("/brand.jsp").forward(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

3.3 增加-增加一条记录

逻辑:通过点击“修改”按钮,跳转到addBrand.jsp页面,在该页面中的表单填写新记录,最后通过“提交”按钮,将数据传到addServlet,addServlet会调用service,service会调用mapper接口中的add方法。
在这里插入图片描述
同样,先写Dao层。在mapper接口中创建add()方法。

    @Insert("insert into tb_brand values(null, #{brandName}, #{companyName}, #{ordered}, #{description}, #{status})")
    void add(Brand brand);

在BrandService中编写add()方法

    public void add(Brand brand){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
        mapper.add(brand);
        sqlSession.commit();
        sqlSession.close();
    }

先写前端页面,在brand.jsp中的“新增”按钮绑定事件,然后事件触发后跳转到addBrand.jsp
按钮:

<input type="button" value="新增" id="add"><br>

通过id绑定事件

<script>
    document.getElementById("add").onclick = function (){
        location.href = "/ServletAndJspCRUDDemo/addBrand.jsp"
    }
</script>

addBrand.jsp就是一个表单,信息填完后,表单会提交到AddServlet

<form action="/ServletAndJspCRUDDemo/addservlet" method="post">
    品牌名称:<input name="brandName"><br>
    企业名称:<input name="companyName"><br>
    排序:<input name="ordered"><br>
    描述信息:<textarea rows="5" cols="20" name="description"></textarea><br>
    状态:
    <input type="radio" name="status" value="0">禁用
    <input type="radio" name="status" value="1">启用<br>

    <input type="submit" value="提交">
</form>

最后编写AddServlet

@WebServlet("/addservlet")
public class AddServlet extends HttpServlet {
    private BrandService service = new BrandService();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // addBrand.jsp的表单通过req传递到servlet,servlet从req获取相应的参数,参数的键就是表单的name。
        req.setCharacterEncoding("utf-8");  // 防止中文乱码
        String brandName = req.getParameter("brandName");
        String companyName = req.getParameter("companyName");
        String ordered = req.getParameter("ordered");
        String description = req.getParameter("description");
        String status = req.getParameter("status");

        // 从req中获取的参数,封装成一个brand实例
        Brand brand = new Brand();
        brand.setBrandName(brandName);
        brand.setCompanyName(companyName);
        brand.setOrdered(Integer.parseInt(ordered));
        brand.setDescription(description);
        brand.setStatus(Integer.parseInt(status));

        // 调用service的方法
        service.add(brand);

        // 处理完后重新将请求转发到“查询所有”页面
        req.getRequestDispatcher("/selectAllServlet").forward(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

3.4 修改-修改记录

修改功能的实现分两步,第一步是点击修改按钮后,要重新读取数据,然后在前端页面显示出来。第二步是修改完成后,重新提交。

3.4.1 数据返显

在这里插入图片描述
Dao层

    @Select("select * from tb_brand where id = #{id}")
    @ResultMap("brandResultMap")
    Brand selectById(int id);

Service层

    public Brand selectById(int id){

        SqlSession sqlSession = sqlSessionFactory.openSession();

        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);

        Brand brand = mapper.selectById(id);

        sqlSession.close();

        return brand;
    }

先写前端。
点击修改按钮后,首先要获得当条记录的id,所以在brand.jsp中的“修改”按钮中传递id

<a href="/ServletAndJspCRUDDemo/selectByIdServlet?id=${brand.id}">修改</a>

SelectByIdServlet

@WebServlet("/selectByIdServlet")
public class SelectByIdServlet extends HttpServlet {

    private BrandService service = new BrandService();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        String id = req.getParameter("id");
        Brand brand = service.selectById(Integer.parseInt(id));
        req.setAttribute("brand", brand);
        req.getRequestDispatcher("/update.jsp").forward(req, resp);

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

最后会将请求转发至update.jsp

<form action="/ServletAndJspCRUDDemo/updateServlet" method="post">

    <input type="hidden" name="id" value="${brand.id}">

    品牌名称:<input name="brandName" value="${brand.brandName}"><br>
    企业名称:<input name="companyName" value="${brand.companyName}"><br>
    排序:<input name="ordered" value="${brand.ordered}"><br>
    描述信息:<textarea rows="5" cols="20" name="description" >${brand.description}</textarea><br>
    状态:
    <c:if test="${brand.status == 0}">
        <input type="radio" name="status" value="0" checked>禁用
        <input type="radio" name="status" value="1">启用<br>
    </c:if>
    <c:if test="${brand.status == 1}">
        <input type="radio" name="status" value="0">禁用
        <input type="radio" name="status" value="1" checked>启用<br>
    </c:if>

    <input type="submit" value="提交">
</form>

这是个表单,通过el表达式从req中读取数据,还使用了jstl的<c:if>标签做判断。

3.4.2 修改提交

在这里插入图片描述
在前端页面完成信息编辑后,通过点击提交按钮,将新记录提交到后台,实质使用的是update sql。
Dao层

    @Update("update tb_brand set brand_name = #{brandName}, company_name = #{companyName}, ordered = #{ordered}, description = #{description}, status = #{status} where id = #{id}")
    void update(Brand brand);

Service层

    public void update(Brand brand){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
        mapper.update(brand);
        sqlSession.commit();
        sqlSession.close();
    }

update.jsp中的表单会提交到UpdateServlet

@WebServlet("/updateServlet")
public class UpdateServlet extends HttpServlet {
    private BrandService service = new BrandService();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        req.setCharacterEncoding("utf-8");

        String id = req.getParameter("id");
        String brandName = req.getParameter("brandName");
        String companyName = req.getParameter("companyName");
        String ordered = req.getParameter("ordered");
        String description = req.getParameter("description");
        String status = req.getParameter("status");

        Brand brand = new Brand();
        brand.setId(Integer.parseInt(id));
        brand.setBrandName(brandName);
        brand.setCompanyName(companyName);
        brand.setOrdered(Integer.parseInt(ordered));
        brand.setDescription(description);
        brand.setStatus(Integer.parseInt(status));

        service.update(brand);

        req.getRequestDispatcher("/selectAllServlet").forward(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

3.4 删除-删除一条记录

Dao层

    @Delete("delete from tb_brand where id = #{id}")
    void delete(int id);

Service层

    public void delete(int id){

        SqlSession sqlSession = sqlSessionFactory.openSession();

        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);

        mapper.delete(id);
        sqlSession.commit();
        sqlSession.close();
    }

前端页面,与“修改”类似,需要获取当条记录的id,通过brand.jsp页面的删除按钮绑定。

<a href="/ServletAndJspCRUDDemo/deleteServlet?id=${brand.id}">删除</a></td>

DeleteServlet

@WebServlet("/deleteServlet")
public class DeleteServlet extends HttpServlet {
    private BrandService brandService = new BrandService();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String id = req.getParameter("id");
        brandService.delete(Integer.parseInt(id));
        req.getRequestDispatcher("/selectAllServlet").forward(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

4 小结

完结撒花!
项目比较简单,但涵盖了web端最基本的增删改查功能,可以用来练习。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java+Servlet+Jsp(el, jstl)+MyBatis的CRUD练习小项目 的相关文章

随机推荐

  • Vue3下pinia的状态管理原理和具体使用示例

    一 Pinia是什么 Pinia在Composition API的设计背景下 以Vuex下一代的构想设计了新的Vue存储状态管理库 Pinia 是一个基于 Vue 3 的状态管理库 它提供了一个可组合的 类型安全的 API 来管理 Vue
  • SpringMVC学习指南(2)

    文章目录 系列文章目录 前言 一 RequestMapping注解 1 1 value属性 1 2 method属性 1 3 params属性 1 4 header属性 1 5 通配符 二 PathVariable 注解 三 REST风格的
  • 安装64位SoildWorks时总是出现无法确定当前的订阅失效日期

    总共会出现两个弹窗信息 弹窗1 安装管理程序无法确定当前的的订阅失效日期 您想重新激活您的许可以更新信息吗 这个弹窗要点击 否 弹窗2 无法决定订阅服务失效日期 您必须使用 这个点击 确定 转载于 https www cnblogs com
  • matlab画对数坐标!

    在很多工程问题中 通过对数据进行对数转换可以更清晰地看出数据的某些特征 在对数坐标系中描绘数据点的曲线 可以直接地表现对数转换 对数转换有双对数坐标转换和单轴对数坐标转换两种 用loglog函数可以实现双对数坐标转换 用semilogx和s
  • 专访《白话区块链》作者蒋勇:学习区块链空谈不如实践

    上周HiBlock区块链社区联合蒋勇老师推出课程 区块链技术概念及智能合约实践 课程上线一天内报名42人 3天时间报名80多人 其中70人通过审核 超额完成第一期招生 为保证学员学习效果 不得已提前关闭报名通道 近几天来 很多学员还在留言问
  • 用C++实现数组切片

    这里写自定义目录标题 用C 实现数组切片 写的一般 权当抛砖引玉了 int slice int arr const int n int a new int n for
  • ubuntu20.4编译AOSP安卓源码(AndroidP android-9.0.0_r9)

    目录 代码下载 安装初始化依赖工具 配置repo工具 配置git信息 初始化仓库 配置编译环境 安装jdk 安装编译依赖 编译 初始化编译环境 选择编译目标 编译源码 启动模拟器 windows和Linux协同工作 遇到的问题解决 安装依赖
  • /etc/sysctl.conf 调优 & 优化Linux内核参数

    from http apps hi baidu com share detail 15652067 http keyknight blog 163 com blog static 3663784020104152407759 http bl
  • vue + video.js 加载多种视频流(HLS、FLV、RTMP、RTSP)

    起因 由于需要在一个项目内接入多种常用的视频流 所以接触到video js 这里就做个记录 框架 vue2 video js videojs contrib hls videojs flvjs es6 videojs flash video
  • 微信小程序支付 java

    话不多说 直接开撸 支付流程步骤 1 首先调用wx login方法获取code 通过code获取openid 2 java后台调用统一下单支付接口 这里会进行第一次签名 用来获取prepay id 3 java后台再次调用签名 这里会进行第
  • 锁升级过程和原理

    目录 同步方法与一般方法字节码对比 对象头中的锁信息 锁升级中涉及的四种锁 锁升级的过程 锁升级过程和原理 同步方法与一般方法字节码对比 public class SynchronizedTest1 public static void m
  • Linux权限详解

    你好 我是史丰源 欢迎你的来访 希望我的博客能给你带来一些帮助 我的Gitee 代码仓库 Linux权限 Shell外壳程序运行原理 Shell 外壳 相当于一层遮蔽内部的保护壳 Linux是一个操作系统 请大家思考一个问题 我们 操作系统
  • pytest参数化实现DDT:读取JSON数据

    JSON JavaScript Object Notation JS 对象简谱 是一种轻量级的数据交换格式 与上一篇文章类似 使用pytest中的pytest mark parametrize 便可实现参数化 代码如下所示 导入json模块
  • conda新建、复制、删除、重命名envs环境

    1 新建环境 conda create n torch python 3 6 这样就创建好了一个名叫torch的python3 6环境 2 复制环境 conda create n new torch clone torch 这样就将torc
  • 【PSO-LSTM】基于PSO优化LSTM网络的电力负荷预测(Python代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 1 1 LSTM神经网络算法 1 2 PSO算法 1 3 PSO LSTM负荷预测模型 2 运行结果 2
  • pytorch: 转onnx模型

    摘要 onnx Open Neural Network Exchange 主要用于部署 训练一般使用pytorch和tensorflow 等训练完成 我们需要模型转成onnx 用于部署在云或者边缘计算上 而为什么要要转成onnx模型呢 主要
  • vscode CommandNotFoundError: Your shell has not been properly configured to use ‘conda activate‘.解决

    1 问题出现 已安装anaconda并已添加其环境变量 测试在win cmd中输入conda及相关conda activate命令等都是正常的 但当在vscode中run debug工程py脚本时出现以下错误及提示 2 踩坑记录 1 根据提
  • xterm使用详情

    常用配置项 rendererType dom canvas 渲染器类型 当 canvas 渲染器运行过慢时 会回退为 DOM 渲染器 DOM 渲染器下不起作用的功能 Letter spacing Cursor blin cols numbe
  • word页码怎么从第三页开始设置为第一页_Word小技巧

    在使用word编辑文档或者写论文的时候 会涉及到页码的设置 今天粉笔君就来给大家分享一下如何快速正确的设置页码格式 一 第一页为封面 第二页为目录 从第三页开始编码 1 将鼠标固定到文档第二页的第一个字符前 在菜单栏中单击 布局 选项 找到
  • Java+Servlet+Jsp(el, jstl)+MyBatis的CRUD练习小项目

    1 概述 这篇博客主要是分享一个基于Servlet Jsp el jstl MyBatis的CRUD练习小项目 包括项目的源码 以及项目的逻辑 通过这个项目能够学习Java web中最基础的servlet jsp和mybatis的使用 为后