JavaWeb快速入门:基于MyBatis综合案例环境搭建与查询所有功能实现

【免费Web系列】JavaWeb实战项目案例二 在前面我们学习MySQL数据库时,使用图形化客户端工具(如:idea、MySQL Workbench),来操作数据库的。在客户端工具中,编写增删改查的SQL语句,发给MySQL数据库管理系统,由数据库管理系统执行SQL语句并返回执行结果。增删改操作:返回受影响行数查询操作:返回结果集(查询的结果)我们做为后端程序开发人员,通常会使用Java程序来完成对数据库的操作。Java程序操作数据库的技术呢,有很多啊。 阅读详情

本文纲要

  1. 环境搭建和项目结构设计
  2. 查询所有品牌
    后台实现
    前端实现
  3. 新增品牌
    后台实现
    前端实现
  4. Servlet 代码优化
    问题分析
    BaseServlet 实现
    改造 BrandServlet
  5. 批量删除
    后台实现
    前端实现
  6. 分页查询
    核心概念分析
    后台实现
    前端实现
  7. 条件查询
    业务分析
    后台实现(动态 SQL + 分页)
    前端实现
  8. 前端代码优化(箭头函数)
  9. 项目结构总览
  10. 总结

环境搭建和项目结构设计

在正式开始开发之前,需要准备好基础工程和数据库环境。

1 ) 导入初始工程

素材中提供了一个名为 brand-case 的 Maven 工程,该工程已经配置好了 MyBatis、Servlet、Fastjson 等依赖,并提供了基础包结构和前端页面。主要依赖如下:

  • MyBatis 3.5.5:持久层框架
  • MySQL 驱动:数据库连接
  • Fastjson 1.2.62:JSON 序列化工具
  • Servlet 3.1.0:Web 层基础
  • Log4j:日志输出

2 ) 执行数据库脚本

在资料中有一个 tb_brand 的 SQL 脚本,它会先删除已存在的同名表,再创建新表并插入 48 条测试数据,为后续分页功能提供数据基础。复制脚本到 Navicat 等工具中执行即可。

执行后表中包含以下字段:

字段名类型说明
idint主键(自增)
brand_namevarchar品牌名称
company_namevarchar企业名称
orderedint排序字段
descriptionvarchar描述信息
statusint状态 0禁用 1启用

数据库准备好后,环境搭建完成。

3 )项目结构总览

brand-case 
├── pom.xml 
├── src 
│   ├── main 
│   │   ├── java/com/wb 
│   │   │   ├── mapper 
│   │   │   │   └── BrandMapper.java          # MyBatis Mapper 接口 
│   │   │   ├── pojo 
│   │   │   │   ├── Brand.java                # 品牌实体类 
│   │   │   │   └── PageBean.java             # 分页包装类 
│   │   │   ├── service 
│   │   │   │   ├── BrandService.java         # 业务接口 
│   │   │   │   └── impl 
│   │   │   │       └── BrandServiceImpl.java # 业务实现类 
│   │   │   ├── util 
│   │   │   │   └── SqlSessionFactoryUtils.java # MyBatis 工具类 
│   │   │   └── web/servlet 
│   │   │       ├── BaseServlet.java          # 自定义分发基类 
│   │   │       ├── BrandServlet.java         # 品牌核心控制器 
│   │   │       ├── UserServlet.java          # 示例(其他实体)
│   │   │       └── old 
│   │   │           ├── AddServlet.java       # 优化前的新增 Servlet 
│   │   │           └── SelectAllServlet.java # 优化前的查询 Servlet 
│   │   ├── resources 
│   │   │   ├── mybatis-config.xml            # MyBatis 核心配置 
│   │   │   ├── log4j.properties 
│   │   │   └── com/wb/mapper 
│   │   │       └── BrandMapper.xml           # 动态 SQL 映射文件 
│   │   └── webapp 
│   │       ├── brand.html                    # 品牌管理前端页面 
│   │       ├── js/
│   │       └── WEB-INF/web.xml 

查询所有品牌

查询所有功能的后台流程:BrandMapper → BrandService → BrandServlet,前端页面加载完成后发送异步请求,获取 JSON 数据并绑定到表格模型上。

1 ) 后台代码

BrandMapper 接口

public interface BrandMapper {
    @Select("select * from tb_brand")
    @ResultMap("brandResultMap")
    List<Brand> selectAll();
}

在 MyBatis 核心配置文件中已经配置了 resultMap,用于映射下划线字段与驼峰属性:

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

BrandService 接口与实现

public interface BrandService {
    List<Brand> selectAll();
}
public class BrandServiceImpl implements BrandService {
    SqlSessionFactory factory = SqlSessionFactoryUtils.getSqlSessionFactory();
 
    @Override 
    public List<Brand> selectAll() {
        SqlSession sqlSession = factory.openSession();
        BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
        List<Brand> brands = mapper.selectAll();
        sqlSession.close();
        return brands;
    }
}

原始 SelectAllServlet(优化前)

@WebServlet("/selectAllServlet")
public class SelectAllServlet extends HttpServlet {
    private BrandService brandService = new BrandServiceImpl();
 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
        List<Brand> brands = brandService.selectAll();
        String jsonString = JSON.toJSONString(brands);
        response.setContentType("text/json;charset=utf-8");
        response.getWriter().write(jsonString);
    }
}

启动 Tomcat 后,直接访问 /selectAllServlet 若返回 JSON 数组,则后台代码正确。

2 ) 前端代码

前端页面使用 Vue.js 配合 Element UI,在 mounted 生命周期中发送异步请求,并将数据设置到 tableData 模型上。

<script>
new Vue({
    el: "#app",
    mounted() {
        this.selectAll();
    },
    methods: {
        selectAll() {
            var _this = this;
            axios({
                method: "get",
                url: "http://localhost:8080/brand-case/selectAllServlet"
            }).then(function (resp) {
                _this.tableData = resp.data;
            });
        }
    },
    data() {
        return {
            tableData: []
        }
    }
});
</script>

注意:axios 回调中无法直接使用 this,需要用 _this 保存 Vue 实例引用。

至此,查询所有功能完成,页面可以展示全部 48 条品牌数据。

新增品牌

新增功能的前后端交互流程如下:

数据库BrandMapperBrandServiceAddServlet/BrandServlet浏览器(brand.html)数据库BrandMapperBrandServiceAddServlet/BrandServlet浏览器(brand.html)POST 提交品牌 JSON 数据读取请求体,JSON → Brand 对象add(brand)add(brand)INSERT INTO tb_brand ...成功voidvoidresponse "success"关闭对话框、重新查询数据、提示成功

1 ) 后台代码

BrandMapper 添加方法

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

BrandService 接口与实现

void add(Brand brand);
@Override 
public void add(Brand brand) {
    SqlSession sqlSession = factory.openSession();
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    mapper.add(brand);
    sqlSession.commit();  // 增删改必须提交事务 
    sqlSession.close();
}

AddServlet(优化前)

@WebServlet("/addServlet")
public class AddServlet extends HttpServlet {
    private BrandService brandService = new BrandServiceImpl();
 
    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
        BufferedReader br = request.getReader();
        String params = br.readLine();                // JSON 字符串 
        Brand brand = JSON.parseObject(params, Brand.class);
        brandService.add(brand);
        response.getWriter().write("success");
    }
}

2 ) 前端代码

表单数据已通过 v-model 与 brand 模型进行双向绑定,点击“提交”按钮时调用 addOrUpdateBrand 方法(本文只演示新增,修改留给读者练习):

addOrUpdateBrand() {
    if (!this.brand.id) {                    // 新增判断 
        var _this = this;
        axios({
            method: "post",
            url: "http://localhost:8080/brand-case/brand/add",
            data: _this.brand 
        }).then(function (resp) {
            if (resp.data == "success") {
                _this.dialogVisible = false;   // 关闭弹窗 
                _this.selectAll();             // 重新查询 
                _this.$message({
                    message: '恭喜你,添加成功',
                    type: 'success'
                });
            }
        });
    }
}

关键点:提交成功后必须关闭对话框、刷新列表、给出成功提示。

Servlet 代码优化

1 ) 问题分析

原始写法中,每个业务功能(查询所有、新增、删除等)都需要单独编写一个 Servlet,例如 SelectAllServlet、AddServlet…… 这样会导致 Web 层 Servlet 数量爆炸,不易维护。

参考 MyBatis 中将所有操作方法集中在一个 Mapper 接口的做法,我们也希望将同一实体(如 Brand)的所有操作集中在一个 Servlet 中,通过请求路径中的最后一段来区分具体方法。例如:

  • /brand/selectAll → 执行 selectAll() 方法
  • /brand/add → 执行 add() 方法

为此,我们需要自定义一个 BaseServlet,替换 HttpServlet 中根据请求方式(GET/POST)分发的方法,改为根据请求路径最后一段进行方法分发。

2 ) BaseServlet 实现

BaseServlet 继承 HttpServlet,重写 service 方法,核心逻辑:

  1. 获取请求 URI,如 /brand-case/brand/selectAll
  2. 截取最后一个 / 之后的部分作为方法名(selectAll)
  3. 通过反射获取当前子类(如 BrandServlet)的 Method 对象
  4. 调用方法,传入 request 和 response
public class BaseServlet extends HttpServlet {
    @Override 
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 获取请求路径 
        String uri = req.getRequestURI();  // /brand-case/brand/selectAll 
        // 2. 获取方法名 
        int index = uri.lastIndexOf('/');
        String methodName = uri.substring(index + 1); // selectAll 
        // 3. 获取子类字节码并调用方法 
        Class<? extends BaseServlet> cls = this.getClass();
        try {
            Method method = cls.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
            method.invoke(this, req, resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

注意:this 在 BaseServlet 中代表实际调用的子类实例(如 BrandServlet),因为 service 方法是被子类调用的。

3 ) 改造 BrandServlet

让 BrandServlet 继承 BaseServlet,并配置 @WebServlet("/brand/*"),这样所有以 /brand/ 开头的请求都会映射到该 Servlet。

将之前 SelectAllServlet 和 AddServlet 中的方法迁移过来:

@WebServlet("/brand/*")
public class BrandServlet extends BaseServlet {
    private BrandService brandService = new BrandServiceImpl();
 
    public void selectAll(HttpServletRequest request, HttpServletResponse response) throws IOException {
        List<Brand> brands = brandService.selectAll();
        String jsonString = JSON.toJSONString(brands);
        response.setContentType("text/json;charset=utf-8");
        response.getWriter().write(jsonString);
    }
 
    public void add(HttpServletRequest request, HttpServletResponse response) throws IOException {
        BufferedReader br = request.getReader();
        Brand brand = JSON.parseObject(br.readLine(), Brand.class);
        brandService.add(brand);
        response.getWriter().write("success");
    }
}

前端对应的请求路径也需修改:

  • 查询所有:/brand/selectAll
  • 新增:/brand/add

这样我们就完成了 Servlet 层的优化,同一实体的操作集中管理,后续添加新方法只需在 BrandServlet 中增加对应方法即可。

批量删除

1 ) 业务分析

用户勾选多条记录后点击“批量删除”,需要将选中项的 ID 数组发送到后端,后端根据 ID 列表执行批量删除。SQL 使用 IN 配合动态 foreach 生成占位符。

2 ) 后台代码

BrandMapper 接口与 XML

void deleteByIds(@Param("ids") int[] ids);
<delete id="deleteByIds">
    delete from tb_brand where 
    <foreach collection="ids" item="id" separator="," open="id in(" close=")">
        #{id}
    </foreach>
</delete>

BrandService 实现

@Override 
public void deleteByIds(int[] ids) {
    SqlSession sqlSession = factory.openSession();
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    mapper.deleteByIds(ids);
    sqlSession.commit();
    sqlSession.close();
}

BrandServlet 方法

public void deleteByIds(HttpServletRequest request, HttpServletResponse response) throws IOException {
    BufferedReader br = request.getReader();
    String params = br.readLine();
    int[] ids = JSON.parseObject(params, int[].class);
    if (ids.length != 0) {
        brandService.deleteByIds(ids);
    }
    response.getWriter().write("success");
}

3 ) 前端代码

Element UI 表格的 @selection-change 事件会将选中数据集合存入 multipleSelection。需要从中提取 ID 数组,并在确认后发送请求。

deleteByIds() {
    // 从 multipleSelection 中提取 ID 数组 
    for (let i = 0; i < this.multipleSelection.length; i++) {
        this.selectedIds[i] = this.multipleSelection[i].id;
    }
    if (this.selectedIds.length == 0) {
        this.$message.error('最少勾选一个');
        return;
    }
    // 确认提示框 
    this.$confirm('此操作将删除该数据, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
    }).then(() => {
        var _this = this;
        axios({
            method: "post",
            url: "http://localhost:8080/brand-case/brand/deleteByIds",
            data: _this.selectedIds 
        }).then(function (resp) {
            if (resp.data == "success") {
                _this.selectedIds = [];
                _this.selectAll();
                _this.$message({ message: '恭喜你,删除成功', type: 'success' });
            }
        });
    }).catch(() => {
        this.$message({ type: 'info', message: '已取消删除' });
    });
}

分页查询

1 )核心概念分析

分页查询需后端返回两部分数据:当前页数据集合 和 总记录数。
前端传递两个参数:当前页码 (currentPage) 和 每页显示条数 (·pageSize·)。

数据库使用 LIMIT 实现物理分页:

SELECT * FROM tb_brand LIMIT 起始索引, 查询条目数;

计算公式:

  • 起始索引 = (当前页码 - 1) × 每页条数
  • 查询条目数 = 每页显示条数

例如:第 2 页,每页 5 条,起始索引 = (2-1)×5 = 5,查询 5 条,SQL 为 LIMIT 5,5。

为统一封装,我们创建 PageBean<T> 对象:

public class PageBean<T> {
    private int totalCount;   // 总记录数 
    private List<T> rows;     // 当前页数据 
    // getter & setter ...
}

前后端交互流程:

数据库BrandMapperBrandServiceBrandServlet前端数据库BrandMapperBrandServiceBrandServlet前端GET/POST currentPage&pageSizeselectByPage(currentPage, pageSize)计算起始索引 begin = (page-1)*sizeselectByPage(begin, size)SELECT * FROM tb_brand LIMIT begin,size结果集selectTotalCount()SELECT count(*) FROM tb_brand总数PageBean(rows, totalCount)JSON 数据更新表格、分页条

2 ) 后台代码

BrandMapper 分页方法

@Select("select * from tb_brand limit #{begin}, #{size}")
@ResultMap("brandResultMap")
List<Brand> selectByPage(@Param("begin") int begin, @Param("size") int size);
 
@Select("select count(*) from tb_brand")
int selectTotalCount();

BrandService 实现

@Override 
public PageBean<Brand> selectByPage(int currentPage, int pageSize) {
    SqlSession sqlSession = factory.openSession();
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    int begin = (currentPage - 1) * pageSize;
    List<Brand> rows = mapper.selectByPage(begin, pageSize);
    int totalCount = mapper.selectTotalCount();
    sqlSession.close();
    PageBean<Brand> pageBean = new PageBean<>();
    pageBean.setRows(rows);
    pageBean.setTotalCount(totalCount);
    return pageBean;
}

BrandServlet 分页查询方法

public void selectByPage(HttpServletRequest request, HttpServletResponse response) throws IOException {
    String _currentPage = request.getParameter("currentPage");
    String _pageSize = request.getParameter("pageSize");
    int currentPage = Integer.parseInt(_currentPage);
    int pageSize = Integer.parseInt(_pageSize);
    PageBean<Brand> pageBean = brandService.selectByPage(currentPage, pageSize);
    String jsonString = JSON.toJSONString(pageBean);
    response.setContentType("text/json;charset=utf-8");
    response.getWriter().write(jsonString);
}

3 ) 前端代码

Element UI 提供了 <el-pagination> 分页组件,我们将其绑定到 currentPage、pageSize、totalCount 属性,并通过 @current-change 和 @size-change 事件重新调用 selectAll 查询。

methods: {
    selectAll() {
        var _this = this;
        axios({
            method: "post",
            url: "http://localhost:8080/brand-case/brand/selectByPageAndCondition?currentPage=" + this.currentPage + "&pageSize=" + this.pageSize,
            data: this.brandSearch 
        }).then(function (resp) {
            _this.tableData = resp.data.rows;       // 当前页数据 
            _this.totalCount = resp.data.totalCount; // 总记录数 
        });
    },
    handleSizeChange(val) {
        this.pageSize = val;
        this.selectAll();
    },
    handleCurrentChange(val) {
        this.currentPage = val;
        this.selectAll();
    }
},
data() {
    return {
        currentPage: 1,
        pageSize: 5,
        totalCount: 100,   // 初始值,实际会被覆盖 
        tableData: []
    }
}

页面首次加载、切换页码或每页条数时均会重新请求数据,实现了完整的分页功能。

条件查询

1 ) 业务分析

条件查询需要根据品牌名称、企业名称、状态三个条件进行模糊匹配,并且这些条件不是必填的(即可按任意组合查询)。查询结果同样需要分页。

因此,后台需使用 MyBatis 动态 SQL 构建查询语句,结合 where 和 if 标签,并在查询后加上 limit 进行分页。

条件查询请求中既有 URL 参数(currentPage、pageSize),又有请求体 JSON 数据(封装为 Brand 对象),因此 BrandServlet 中需要分别获取。

流程示意图:

DBMapperServiceServletBrowserDBMapperServiceServletBrowserPOST /brand/selectByPageAndCondition?currentPage=1&pageSize=5Body:{"brandName":"华为","status":1}获取 currentPage/pageSize (GET参数)读取请求体转 Brand 对象selectByPageAndCondition(currentPage,pageSize,brand)处理模糊查询(添加 %)selectByPageAndCondition(begin,size,brand)动态SQL + LIMITselectTotalCountByCondition(brand)带条件的 count(*)PageBeanJSON

2 ) 后台代码

BrandMapper 接口

List<Brand> selectByPageAndCondition(@Param("begin") int begin,
                                     @Param("size") int size,
                                     @Param("brand") Brand brand);
 
int selectTotalCountByCondition(Brand brand);

BrandMapper.xml 动态 SQL

<select id="selectByPageAndCondition" resultMap="brandResultMap">
    select * from tb_brand 
    <where>
        <if test="brand.brandName != null and brand.brandName != '' ">
            and brand_name like #{brand.brandName}
        </if>
        <if test="brand.companyName != null and brand.companyName != '' ">
            and company_name like #{brand.companyName}
        </if>
        <if test="brand.status != null">
            and status = #{brand.status}
        </if>
    </where>
    limit #{begin}, #{size}
</select>
 
<select id="selectTotalCountByCondition" resultType="int">
    select count(*) from tb_brand 
    <where>
        <if test="brandName != null and brandName != '' ">
            and brand_name like #{brandName}
        </if>
        <if test="companyName != null and companyName != '' ">
            and company_name like #{companyName}
        </if>
        <if test="status != null">
            and status = #{status}
        </if>
    </where>
</select>

注意:selectByPageAndCondition 中因为使用了 @Param("brand"),所以 OGNL 表达式需写成 brand.brandName;而 selectTotalCountByCondition 直接传入 Brand 对象,未加 @Param,因此直接用属性名即可。

BrandService 实现

@Override 
public PageBean<Brand> selectByPageAndCondition(int currentPage, int pageSize, Brand brand) {
    SqlSession sqlSession = factory.openSession();
    BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
    int begin = (currentPage - 1) * pageSize;
 
    // 处理模糊查询:前后拼接 %
    if (brand.getBrandName() != null && !brand.getBrandName().isEmpty()) {
        brand.setBrandName("%" + brand.getBrandName() + "%");
    }
    if (brand.getCompanyName() != null && !brand.getCompanyName().isEmpty()) {
        brand.setCompanyName("%" + brand.getCompanyName() + "%");
    }
    // 防止 brand 为 null 引发空指针 
    if (brand == null) {
        brand = new Brand();
    }
 
    List<Brand> rows = mapper.selectByPageAndCondition(begin, pageSize, brand);
    int totalCount = mapper.selectTotalCountByCondition(brand);
    sqlSession.close();
 
    PageBean<Brand> pageBean = new PageBean<>();
    pageBean.setRows(rows);
    pageBean.setTotalCount(totalCount);
    return pageBean;
}

BrandServlet 条件分页查询方法

public void selectByPageAndCondition(HttpServletRequest request, HttpServletResponse response) throws IOException {
    String _currentPage = request.getParameter("currentPage");
    String _pageSize = request.getParameter("pageSize");
    int currentPage = Integer.parseInt(_currentPage);
    int pageSize = Integer.parseInt(_pageSize);
 
    // 读取请求体中的条件 JSON 
    BufferedReader br = request.getReader();
    Brand brand = JSON.parseObject(br.readLine(), Brand.class);
 
    PageBean<Brand> pageBean = brandService.selectByPageAndCondition(currentPage, pageSize, brand);
    String jsonString = JSON.toJSONString(pageBean);
    response.setContentType("text/json;charset=utf-8");
    response.getWriter().write(jsonString);
}

3 ) 前端代码

查询表单通过 v-model="brandSearch" 绑定了一个条件对象,点击查询按钮时调用 onSubmit 方法,该方法会触发 selectAll(此时已改为条件分页查询),并将 brandSearch 作为请求体发送。

data() {
    return {
        brandSearch: {
            status: '',
            brandName: '',
            companyName: ''
        }
    }
},
methods: {
    onSubmit() {
        this.selectAll();   // 会携带 brandSearch 条件 
    },
    selectAll() {
        var _this = this;
        axios({
            method: "post",
            url: "http://localhost:8080/brand-case/brand/selectByPageAndCondition?currentPage=" + this.currentPage + "&pageSize=" + this.pageSize,
            data: this.brandSearch 
        }).then(function (resp) {
            _this.tableData = resp.data.rows;
            _this.totalCount = resp.data.totalCount;
        });
    }
}

表格中当前状态显示汉字使用了 Brand 实体中的逻辑视图 getStatusStr(),前端直接绑定 statusStr 属性即可。

前端代码优化

在 axios 的回调函数中,如果使用 function 定义回调,内部的 this 会丢失 Vue 实例,需要提前用 _this 保存。ES6 提供了箭头函数,它可以自动绑定上下文的 this,使代码更简洁。

优化前:

axios({ ... }).then(function (resp) {
    _this.tableData = resp.data.rows;
});

优化后:

axios({ ... }).then(resp => {
    this.tableData = resp.data.rows;
});

项目中所有 axios 调用均可替换为箭头函数,不再需要 _this 中转。

总结

本篇通过一个完整的品牌管理案例,串联了 JavaWeb 阶段的核心技术:

  • MyBatis:接口 + XML 实现增删改查,动态 SQL(where、if、foreach)处理复杂条件与批量操作。
  • Servlet:通过自定义 BaseServlet 实现了基于路径的方法分发,避免了 Servlet 数量膨胀。
  • JSON 交互:使用 Fastjson 在前后端之间传递对象数据。
  • 分页查询:利用 LIMIT 和 PageBean 封装,配合前端分页组件,实现物理分页。
  • 条件查询:动态 SQL 实现多条件模糊查询,并整合分页功能。
  • 前端(Vue + Element UI):数据双向绑定、表格、对话框、分页条的使用,以及箭头函数优化。
  • 三层架构:Mapper(持久层) → Service(业务层) → Servlet(表现层),职责清晰,易于扩展。

掌握了这些基础之后,未来切换到 Spring + SpringMVC + MyBatis 等框架时,原理相通,上手会非常容易。

VSCode配置JavaWeb开发环境:从环境搭建到项目部署全指南 Java Web开发是构建企业级应用的核心技术栈,其原理基于Java EE规范,通过Servlet、JSP等技术处理HTTP请求与响应。在开发实践中,集成开发环境(IDE)的选择直接影响开发效率与体验。Visual Studio Code(VSCode)作为一款轻量级、高扩展性的代码编辑器,凭借其强大的插件生态,能够通过配置转变为高效的Java开发工具,尤其适合需要快速启动、多语言切换或偏好轻量化工具的开发者。本文聚焦于VSCode这一热词,详细解析如何将其配置为专业的JavaWeb开发环境,涵盖JDK、M 阅读详情

相关推荐

SSM框架快速入门:MyBatis与JavaWeb整合教程

SSM框架是Spring、SpringMVC和MyBatis三大框架的组合简称,是目前主流的Java EE企业级应用开发框架。它以Spring为核心,整合了SpringMVC和MyBatis两个子框架,实现了表现层、业务层和持久层的解耦,使得系统各层的职责更加清晰,便于维护和扩展。ORM(Object-Relational Mapping)对象关系映射是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。

weixin_34640289的博客 1019

Mybatis开发环境搭建与配置

在resources下创建db.properties。

m0_72380971的博客 1586

C#中iBatis连接mySQL使用的DLL

C#中iBatis连接mySQL使用的DLL

MyBatis环境搭建以及简单案例运行

MyBatis环境搭建以及案例运行

m0_63879480的博客 248

Ubuntu Server 24.04 安装 (超详细)

本文介绍最小化安装 Ubuntu Server的详细过程。

炀炀的专栏 1万+

应用软件——Altium Designer 19 Gerber/坐标文件

如何输出Gerber文件 步骤如下: 打开需要输出的PCB文件 2. 设置原点坐标 3. 打开Gerber Files 选项,File–>Fabrication Opuputs–>Gerber Files。 4. General参数设置。 用于指定输出Gerber文件中使用的单位(Units)和格式(Format)。单位可以是公制(Millimeters)和英制(Inches);格式栏中2:3,2:4,2:5代表文件中使用的不同数据精度,其中2:3表示数据含2位整数3位小数;相应的,另外两个分

染血黑兔的博客 7203

Java web 开发常用的框架详解

Spring是Java开发中最流行的企业级框架之一。它提供了全面的基础设施支持,包括依赖注入(DI)、面向切面编程(AOP)、事务管理、数据访问等。Spring框架的核心是Spring IoC容器,它管理对象的生命周期和配置。

Itmastergo的博客 1万+

2022-2028年中国美容仪行业发展战略规划及投资机会预测报告

报告类型:产业研究 报告格式:电子版、纸介版 出品单位:智研咨询-产业信息网 美容仪是一种根据人体生理机能进行调节改善身体和面部的机器,它按照功能来说有美白、嫩肤、祛斑、祛皱、脱毛、减肥等多种,按照名称来说有超声波导入、光子嫩肤、高周波电疗、RF 电波拉皮、电子祛斑点痣、E 光永久脱毛嫩肤、贾法尼营养导入导出等。 智研咨询发布的《2022-2028年中国美容仪行业发展战略规划及投资机会预测报告》共十七章。首先介绍了中国美容仪行业市场发展环境、美容仪整体运行态势等,接着分析了中...

kt346的博客 468

MyBatis开发环境搭建与配置

6.1 com.example.mapper.UserMapper.java接口文件中添加方法。6.3com.example.test.TestMybatis.java中添加测试方法。5.创建MyBatis核心配置文件(mybatis-config.xml)3.修改核心配置文件(mybatis-config.xml)三、修改核心配置文件(mybatis-config.xml)4.创建映射文件(UserMapper.xml)四、创建映射文件(UserMapper.xml)2.引入相关依赖(pom.xml)

qq_46530609的博客 2376

FPGA时序分析中的工艺角:从PVT原理到建立保持时间验证

在数字电路设计中,静态时序分析(STA)是确保芯片功能正确和性能达标的核心验证手段。其基本原理是通过计算信号在逻辑路径上的传播延迟,检查建立时间和保持时间是否满足寄存器采样要求。这项技术的核心价值在于,它能在芯片制造前就预测并消除时序违规,极大提高设计成功率。然而,实际芯片性能会受到工艺波动、电压变化和温度漂移(合称PVT)的显著影响。为了覆盖这些不确定性,时序分析必须采用基于工艺角的边界模型——用最慢的工艺角模型验证建立时间,用最快的工艺角模型验证保持时间。这种分析方法广泛应用于FPGA和ASIC设计流程

weixin_30181209的博客 198

从零开始使用CubeMX配置STM32使用lwip实现httpd服务器以及使用vscode编辑阅读keil代码(三)

使用stm32搭载lwip实现HTTPd服务器

qq_30623327的博客 5933

Mybatis环境的搭建

7、添加SqlSessionFactoryUtils工具类,用于加载mybatis-config.xml文件,并创建出SqlSessionFactory。5、在resources下创建文件,路径如下(和mapper接口的路径一致)4、在resource下新建一个mybatis-config.xml文件。3、在项目中创建一个mapper包,存放查询数据库的接口。1、导入mybatis的依赖坐标和数据库链接。6、在刚才创建的文件夹下创建对应的xml文件。2、在项目中创建entity实体类。

qq_57907966的博客 602

Python-OpenCV及cv2,numpy库最新安装教程[最全步骤]

安装教程目录前言OpenCV-Python安装教程报错解决cv2安装numpy安装opencv安装(附加)总结 前言 首先,我知道一些看到我的Blog的人已经在网上找了很多歪路子,现在已经火冒三丈了(我也是这样过来的hhhh),那么现在,深呼吸,跟着我的教程,不要着急,每一步都要读一遍。完整安装过程需要1个小时左右(仅供参考,本人第一次安装python花了一天(确信)) OpenCV-Python...

qq_45425286的博客 7430

【黑马】JavaWeb开发教程(涵盖Spring+MyBatis+SpringMVC+SpringBoot等)目录合集

黑马程序员2023新版JavaWeb开发教程目录合集,实现javaweb企业开发全流程(涵盖Spring+MyBatis+SpringMVC+SpringBoot等)。

汤姆lazy的优快云博客 4万+

PCL 区域生长分割【2026最新版】

区域生长算法原理介绍、代码实现以及一个具体实验场景的应用案例进一步实现将分割结果的分类保存至本地文件夹。最近一次更新时间为:2026年5月4日。

点云侠的博客 40万+

数学建模学习(121):Python实现模糊AHP(Fuzzy AHP)——从原理到实践

Python实现模糊AHP(Fuzzy AHP)

全栈川川 1541

JavaWeb基础教程,JavaWeb从入门到实战

数据库连接池是个容器,负责分配、管理数据库连接它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接二引起的数据库连接遗漏好处:资源重用提升系统响应速度避免数据库资源遗漏。

m0_54068390的博客 1170

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

[JavaWeb玩耍日记]Mybatis快速入门与增删改查

实体类的属性与表的列名冲突不一样时,mybatis不能自动封装数据,导致查询结果某列为null 比如mysql表的列名为brand_name,java类中变量名为brandName。这个文件相当于为指定的mapper接口写具体实现,主要内容是写sql语句,还需要指定对应的接口(是哪一个mapper)与返回数据的类型(是哪一个pojo)目标:查询USER表中的所有数据与查询id为1的数据(以下内容有部分操作为非必要操作,有其余更多的解决方案,提出的问题仅用于加深记忆)

m0_63186780的博客 1140

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

全网最强JavaWeb笔记 | 万字长文爆肝JavaWeb开发——day08数据库Mybatis入门

万字长文爆肝黑马程序员2023最新版JavaWeb教程。这套教程打破常规,不再局限于过时的老套JavaWeb技术,而是与时俱进,运用的都是企业中流行的前沿技术。笔者认真跟着这个教程,再一次认真学习一遍JavaWeb教程,温故而知新,对JavaWeb开发也有了更加深入细致的了解。因此笔者做了全网最全面详细的学习笔记,通篇图文并茂,

qq_45832461的博客 1645

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

黑马JavaWeb开发跟学(八)MySQL多表查询以及MyBatis基础

MySQL多表查询以及MyBatis基础

心向阳光的天域的博客 1017

黑马2023javaweb(08)|MySQL(多表查询,事务,索引),mybatis入门(简化JDBC开发)

索引:提高查询数据的数据结构但是:一个业务,查询业务占90%以上,这两个缺点就不值一提了【Java Web】009 -- MyBatis(入门 & 增删改查 & 动态SQL)_mybatis新增sql-优快云博客Day08-14. Mybatis-入门-快速入门程序_哔哩哔哩_bilibilispringboot整合mybatis配置数据库,就是将上述操作转换为如下代码配置到application.properties文件中。

leeyayai_xixihah的博客 1192

【JavaWeb 之mybatis】一篇文字带你快速入门Mybatis

什么是MyBatis? 。MyBatis是一款优秀的特久层框架,用于简化JDBC开发 MyBatis本是Apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github 官网:https:l/mybatis.org/mybatis-3/zh/index.html mybatis负责将数据到保存到数据库的那一层代码 JavaEE三层架构:表现层、业务层、持久层框架就是一个

屠一乐的博客 293

JavaWeb: Mybatis及其入门案例

JavaWeb: Mybatis及其入门案例

2201_75736541的博客 211

黑马程序员JavaWeb开发教程(后端部分Mybatis) ---笔记分享

通过Mybatis的快速入门,我们明白了,通过Mybatis可以很方便的进行数据库的访问操作。但是大家 要明白,其实java语言操作数据库呢,只能通过一种方式:使用sun公司提供的JDBC规范。Mybatis框架,就是对原始的JDBC程序的封装。JDBC,就是使用Java语言操作关系型数据库的一套API本质:sun公司官方定义的一套操作所有关系型数据库的规范,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)

蓝桉 1638

javaweb知识点总结(黑马视频笔记)

一篇学完javaweb

m1215339620的博客 8185

08JavaWeb——MySQL-Mybatis入门(多表查询、子查询、事务、索引、mybatis入门、数据库连接池、jdbc、lombok)

多表查询:查询时从多张表中获取所需数据单表查询的SQL语句:select 字段列表 from 表名;那么要执行多表查询,只需要使用逗号分隔多张表即可,如: select 字段列表 from 表1, 表2;此时,我们看到查询结果中包含了大量的结果集,总共85条记录,而这其实就是员工表所有的记录(17行)与部门表所有记录(5行)的所有组合情况,这种现象称之为笛卡尔积。笛卡尔积:笛卡尔乘积是指在数学中,两个集合(A集合和B集合)的所有组合情况。

qq_56947957的博客 1377
上一篇: JavaWeb快速入门:AJAX、Axios与JSON实战
下一篇: Java框架快速入门: 揭开 Spring 核心奥秘(IoC 与 DI)
Wang's Blog
博客等级 码龄12年 7418粉丝 2407原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wang's Blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值