WEB综合案例

环境准备

先创建好web maven工程

搭建好mybatis的框架

(核心配置文件,pom依赖关系)

导入相关的数据库依赖,tomcat依赖还有封装好的sqlSessionFactoryUtils

还有我们写好的页面需要的

image-20220415184212718

准备好数据库

image-20220415184446240

查询所有

image-20220415184656957

在HTML中还要将数据设置到模型上,这样模型一变,显示就变了

DAO

/**
* 查询所有
* @return
*/
@Select("SELECT * FROM tb_brand")
@ResultMap("brandResultMap")
List<Brand> selectAll();

这里因为数据库中的列名和实体类中的名字不一样所以要用resultmap

image-20220415185034128

<mapper namespace="com.ember.mapper.BrandMapper">
<resultMap id="brandResultMap" type="brand">
<result column="brand_name" property="brandName"></result>
<result column="company_name" property="companyName"></result>
</resultMap>
</mapper>

service

这里和之前有点不一样,我们在service是通过写一个接口BrandService再写实现类来完成接口来写的,不像原来直接写成一个实现类(为了配合框架将service和web层解耦合)

image-20220415190809982

public interface BrandService {
/*查询所有*/
List<Brand> selectAll();
}
public class BrandServiceImpl implements BrandService {
//.创建对应的sqlsessionfactory对象
SqlSessionFactory factory= SqlSessionFactoryUtils.getSqlSessionFactory();
@Override
public List<Brand> selectAll() {
//.获取sqlsession对象
SqlSession sqlSession = factory.openSession();
//.获取brandmapper
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
//.调用方法
List<Brand> brands = mapper.selectAll();
//.释放资源
sqlSession.close();
return brands;
}
}

Web

因为要用到json

所以我们要导入依赖

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
@WebServlet(name = "SelectAllServlet", value = "/selectAllServlet")
public class SelectAllServlet extends HttpServlet {
private BrandService brandService=new BrandServiceImpl();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Brand> brands = brandService.selectAll();
//.将集合转化为json,序列化数据
String string = JSON.toJSONString(brands);
//.响应数据,数据带中文所以要设置 response.setContentType("text/json;charset=utf-8");
response.setContentType("text/json;charset=utf-8");
response.getWriter().write(string);
}

随后我们执行tomcat访问selectServlet可以看到数据返回说明成功了(我们小程序中使用的api'就是这个原理)

image-20220415191500450

前端代码

就是在页面中添加ajax(这里我们用的是axios所以要先导入axios.js文件)代码发送异步请求接收数据保存到data中

<script src="js/axios-0.18.0.js"></script>
mounted(){
//.当页面加载之后,发送异步请求获取数据
var _this=this;
axios({
method:"get",
url:"http://localhost:8080/cookie-demo/selectAllServlet"
}).then(function (resp){
_this.tableData= resp.data;
})
}

访问页面,数据成功显示则成功

image-20220415192430762

新增品牌

三成结构代码大同小异

DAO

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

service

/*添加*/
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();
}

WEB

@WebServlet(name = "AddServlet", value = "/addServlet")
public class AddServlet extends HttpServlet {
BrandService brandService=new BrandServiceImpl();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//.接收品牌数据
BufferedReader reader = request.getReader();
String params = reader.readLine();//.json字符串
//.将字符串转为brand对象
Brand brand = JSON.parseObject(params, Brand.class);
//.调用service来添加
brandService.add(brand);
//.响应成功的标识
response.getWriter().write("success");
}

前端

找到对应的按钮对应的方法

image-20220415194114271

因为经常要刷新页面我们直接将相关代码写到一个方法里

//.查询所有的方法
selectAll(){
var _this=this;
axios({
method:"get",
url:"http://localhost:8080/cookie-demo/selectAllServlet"
}).then(function (resp){
_this.tableData= resp.data;
})
}

那么原来写好的mounted就可以改成

mounted(){
//.当页面加载之后,发送异步请求获取数据
this.selectAll();
/* var _this=this;
axios({
method:"get",
url:"http://localhost:8080/cookie-demo/selectAllServlet"
}).then(function (resp){
_this.tableData= resp.data;
})*/
}
addBrand() {
var _this=this
//.发送ajax请求,添加数据
axios({
method: "post",
url: "http://localhost:8080/cookie-demo/addServlet",
data:_this.brand
}).then(function (resp){
if(resp.data=="success"){
//.添加成功
//1.关闭窗口
_this.dialogVisible = false;
//2.重新查询数据
_this.selectAll();
//3.弹出成功提示
_this.$message({
message: '恭喜你,添加成功',
type: 'success'
});
}
})
}

servlet代码优化

问题:WEB层的servlet个数太多了,不利于管理和编写

优化:

将servlet进行归类,对于同一个实体操作方法,写到一个servlet中。比如Brand实体对应BrandServlet,User->UserServlet

image-20220415201627365

我们现在就是要实现根据路径来实现方法分发,那么httpservlet这种根据请求方式实现方法分发的就不能用了

/*替换httpservlet的,根据请求的最后一段路径进行方法分发*/
public class BaseServlet extends HttpServlet {
//.根据请求的最后一段路径进行方法分发
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//.获取请求路径
String uri = req.getRequestURI();// /cookie-demo/brand/selectAll
//.获取最后一段路径(方法名)
int index=uri.lastIndexOf("/");
String methodName = uri.substring(index+1);
//2.执行方法
//2.1获取BrandServlet/UserServlet的字节码对象(class对象)
Class<? extends BaseServlet> cls = this.getClass();
//2.2获取方法 Method对象
try {
Method method= cls.getMethod(methodName,HttpServletRequest.class,HttpServletResponse.class);
try {
//.2.3执行方法
method.invoke(this,req,resp);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
@WebServlet("/brand/*")
public class BrandServlet extends BaseServlet{
private BrandService brandService=new BrandServiceImpl();
public void selectAll(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
List<Brand> brands = brandService.selectAll();
//.将集合转化为json,序列化数据
String string = JSON.toJSONString(brands);
//.响应数据,数据带中文所以要设置 response.setContentType("text/json;charset=utf-8");
resp.setContentType("text/json;charset=utf-8");
resp.getWriter().write(string);
}
public void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//.接收品牌数据
BufferedReader reader = req.getReader();
String params = reader.readLine();//.json字符串
//.将字符串转为brand对象
Brand brand = JSON.parseObject(params, Brand.class);
//.调用service来添加
brandService.add(brand);
//.响应成功的标识
resp.getWriter().write("success");
}
}

再更改页面中的路径image-20220415204801109

image-20220415204812044

修改品牌信息

这里自己完成,我做的时候有几个难点

1.如何点击修改按钮获得当前行的id传给后端

2.如何实现表单中数据的回显

解决方法

1.参考了评论区

image-20220418111639441

实现代码

<el-table-column
label="操作"
align="center"
>
<template slot-scope="scope">
<el-button type="primary" @click="selectById(scope.$index,scope.row)" >修改</el-button>
<el-button type="danger" @click="deleteById(scope.$index,scope.row)" >删除</el-button>
</template>
</el-table-column>

这里我是在data中创建了个对象用于存放后端查询后返回的数据

//修改行的数据
selectBrand:{},
selectById(index,row){
var _this=this;
console.log(row.id)
this.update=true;
axios({
method:"get",
url:"http://localhost:8080/cookie-demo/brand/selectById?id="+row.id
}).then(function (resp){
_this.selectBrand=resp.data;
console.log(_this.selectBrand)
//.显示修改对话框
_this.update=true;
})
}

2.在对话框中设置回显,你看了上面对象你可能不知道为啥要新定义一个对象存数据(为了方便回显),应为vue是模型改变显示直接改变,所以当我们的输入框对应的模型中有数据时,输入框内就会显示出数据

下面给出代码

<!--修改对话框-->
<el-dialog
title="提示"
:visible.sync="update"
width="30%"
:before-close="handleClose"
:rules="rules">
<el-form ref="form" :model="form" label-width="80px" >
<el-form-item label="品牌名称" prop="brandName">
<el-input v-model="selectBrand.brandName" ></el-input>
</el-form-item>
<el-form-item label="企业名称" prop="companyName">
<el-input v-model="selectBrand.companyName"></el-input>
</el-form-item>
<el-form-item label="排序">
<el-input v-model="selectBrand.ordered"></el-input>
</el-select>
</el-form-item>
<el-form-item label="备注">
<el-input type="textarea" v-model="selectBrand.description"></el-input>
</el-form-item>
<el-form-item label="状态">
<el-switch v-model="selectBrand.status"
active-value="1"
inactive-value="0"></el-switch>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="updateBrand" >更新</el-button>
<el-button @click="update=false">取消</el-button>
</el-form-item>
</el-form>
</el-dialog>

效果展示

image-20220418112619032

DAO

/*根据id查询*/
@Select("SELECT * FROM tb_brand WHERE id=#{id}")
@ResultMap("brandResultMap")
Brand selectById(int id);
/*修改数据*/
@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

/*根据id查询*/
Brand selectById(int id);
void update(Brand brand);
@Override
public Brand selectById(int id) {
//.获取sqlsession对象
SqlSession sqlSession = factory.openSession();
//.获取brandmapper
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
//.调用方法
Brand brand = mapper.selectById(id);
//.释放资源
sqlSession.close();
return brand;
}
@Override
public void update(Brand brand) {
SqlSession sqlSession = factory.openSession();
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
mapper.update(brand);
sqlSession.commit();
sqlSession.close();
}

servlet

public void selectById(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// int id =Integer.parseInt(req.getQueryString());
int id =Integer.parseInt(req.getParameter("id")) ;
Brand brand=brandService.selectById(id);
String string = JSON.toJSONString(brand);
resp.setContentType("text/json;charset=utf-8");
resp.getWriter().write(string);
}
public void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//.接收品牌数据
BufferedReader reader = req.getReader();
String params = reader.readLine();//.json字符串
//.将字符串转为brand对象
Brand brand = JSON.parseObject(params, Brand.class);
//.调用service来添加
brandService.update(brand);
// 3.转发到查询所有的servlet
resp.getWriter().write("success");
}

删除和批量删除

DAO

mapper

/*删除数据*/
@Delete("DELETE FROM tb_brand WHERE id=#{id}")
@ResultMap("brandResultMap")
void deleteById(int id);
/*批量删除要用动态sql所以不能使用注解,只能使用xml*/
void deleteByIds(@Param("ids") int[] ids);

service

service接口

/*删除*/
void deleteById(int id);
/*批量删除*/
void deleteByIds(int[] ids);

service实现类

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

servlet

public void deleteById(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int id =Integer.parseInt(req.getParameter("id")) ;
brandService.deleteById(id);
resp.getWriter().write("success");
}
/*批量删除*/
public void deleteByIds(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//.接收品牌数据
BufferedReader reader = req.getReader();
String params = reader.readLine();//.json字符串
//.将字符串转为brand对象
int[] ints = JSON.parseObject(params, int[].class);
//.调用service来添加
brandService.deleteByIds(ints);
//.响应成功的标识
resp.getWriter().write("success");
}

前端

绑定点击事件

image-20220419105434968

image-20220419105601390

在data中增加数组存放被选中的值

image-20220419105659924

方法实现

deleteById(index,row){
var _this=this;
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
axios({
method:"get",
url:"http://localhost:8080/cookie-demo/brand/deleteById?id="+row.id
// data:"id="+_this.brand.id
}).then(function (resp){
if(resp.data=="success"){
//.添加成功
//1.关闭窗口
_this.dialogFormVisible = false;
//2.重新查询数据
_this.selectAll();
//3.弹出成功提示
_this.$message({
message: '恭喜你,删除成功',
type: 'success'
});
}
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
});
});

我们看复选框的代码可以发现每次选中就会将值存入一个数组中

image-20220419105850375

所以我们批量删除可以直接从这个数组中筛选每个值的id

image-20220419110003799

方法实现

deleteByIds(){
//弹出确认的提示框
this.$confirm('此操作将删除该数据, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
//用户点确定按钮
//1.创建id数组[1,2,3],从multipleSelection中获取即可
// console.log(this.multipleSelection)
for (let i = 0; i < this.multipleSelection.length; i++) {
let selectionElement = this.multipleSelection[i];
this.selectedIds[i]=selectionElement.id;
}
//2.发送ajax请求
var _this=this
//.发送ajax请求,添加数据
axios({
method: "post",
url: "http://localhost:8080/cookie-demo/brand/deleteByIds",
data:_this.selectedIds
}).then(function (resp){
if(resp.data=="success"){
//.添加成功
//1.关闭窗口
_this.dialogVisible = false;
//2.重新查询数据
_this.selectAll();
//3.弹出成功提示
_this.$message({
message: '恭喜你,删除成功',
type: 'success'
});
}
})
}).catch(() => {
this.$message({
// 用户点击取消按钮
type: 'info',
message: '已取消删除'
});
})
}

分页查询

sql语句关键字limit

SELECT * FROM LIMIT 参数1,参数2

第一个参数是开始的开始的索引

第二个参数是查询的条目数

页面传递的参数

当前页码 i

每页显示的条数n

第一个参数=(i-1)*n

第二个参数=n

业务逻辑分析

image-20220419111419990

首先完成pagebean类

//.分页查询的JavaBean
import java.util.List;
public class PageBean<T> {
//.总记录数
private int totalCount;
//.当前页的数据
private List<T> rows;
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public List<T> getRows() {
return rows;
}
public void setRows(List<T> rows) {
this.rows = rows;
}
}

后端逻辑

DAO

/*分页查询*/
@Select("SELECT * FROM tb_brand LIMIT #{begin},#{size}")
List<Brand> selectByPage(@Param("begin")int begin,@Param("size")int size);
/*查询总记录数
* */
@Select("SELECT COUNT(*) FROM tb_brand")
int selectTotalCount();

service

/*分页
* @param currentPage 当前页码
* @param pageSize每页展示条数*/
PageBean<Brand> selectByPage(int currentPage,int pageSize);
@Override
public PageBean<Brand> selectByPage(int currentPage, int pageSize) {
SqlSession sqlSession = factory.openSession();
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
//.计算开始索引
int begin=(currentPage-1)*pageSize;
//.查询的条目数
int size=pageSize;
//.查询当前页数据
List<Brand> rows = mapper.selectByPage(begin, size);
//.查询总条数
int totalCount = mapper.selectTotalCount();
//.封装pageBean对象
PageBean<Brand> pageBean=new PageBean<>();
pageBean.setRows(rows);
pageBean.setTotalCount(totalCount);
//.释放资源
sqlSession.close();
return pageBean;
}

servlet

/*分页查询*/
public void selectByPage(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//.从前端接收当前页码和每页展示条数 url?currentPage=1&pageSize=5
String _currentPage = req.getParameter("currentPage");
String _pageSize = req.getParameter("pageSize");
int currentPage = Integer.parseInt(_currentPage);
int pageSize = Integer.parseInt(_pageSize);
PageBean<Brand> pageBean = brandService.selectByPage(currentPage, pageSize);
//.将集合转化为json,序列化数据
String string = JSON.toJSONString(pageBean);
//.响应数据,数据带中文所以要设置 response.setContentType("text/json;charset=utf-8");
resp.setContentType("text/json;charset=utf-8");
resp.getWriter().write(string);
}

后来maven启动传入参数看是否能返回数据

image-20220419141415682

前端代码

增加两个变量用于动态改变当前页显示条数和总条数

image-20220419143649474

selectAll(){
var _this=this;
axios({
method:"get",
url:"http://localhost:8080/cookie-demo/brand/selectByPage?currentPage="+_this.currentPage+"&pageSize="+_this.pageSize+""
}).then(function (resp){
_this.tableData= resp.data.rows;
_this.totalCount=resp.data.totalCount;
})
},

更改点击分页的代码

//分页
handleSizeChange(val) {
// console.log(`每页 ${val} 条`);
this.pageSize=val;
this.selectAll();
},
handleCurrentChange(val) {
// console.log(`当前页: ${val}`);
this.currentPage=val;
this.selectAll();
},

条件查询

要使用动态sql

image-20220419144043231

后端逻辑

image-20220419144401921

DAO

/*分页条件查询*/
List<Brand> selectByPageAndCondition(@Param("begin")int begin,@Param("size")int size,@Param("brand")Brand brand);
/*根据条件查询总记录数*/
int selectTotalCountByCondition(Brand brand);
<!-- WHERE brand_name=#{brand.brandName}-->
<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="java.lang.Integer">
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>

这里的难点就是sql语句的书写(动态sql)

SERVICE

重难点是对数据有模糊处理,这对sql基础有要求

/*分页条件查询
* @param currentPage 当前页码
* @param pageSize每页展示条数*/
PageBean<Brand> selectByPageAndCondition(int currentPage,int pageSize,Brand brand);
@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;
//.查询的条目数
int size=pageSize;
// 因为是模糊查询所以要处理下brand条件(在数据两边加上%)
String brandName = brand.getBrandName();
if(brandName!=null&& brandName.length()>0){
brand.setBrandName("%"+brandName+"%");
}
String companyName = brand.getCompanyName();
if(companyName!=null && companyName.length()>0){
brand.setCompanyName("%"+companyName+"%");
}
//.查询当前页数据
List<Brand> rows = mapper.selectByPageAndCondition(begin, size,brand);
//.查询总条数
int totalCount = mapper.selectTotalCountByCondition(brand);
//.封装pageBean对象
PageBean<Brand> pageBean=new PageBean<>();
pageBean.setRows(rows);
pageBean.setTotalCount(totalCount);
//.释放资源
sqlSession.close();
return pageBean;
}

selvlet

/*分页条件查询*/
public void selectByPageAndCondition(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//.从前端接收当前页码和每页展示条数 url?currentPage=1&pageSize=5
String _currentPage = req.getParameter("currentPage");
String _pageSize = req.getParameter("pageSize");
int currentPage = Integer.parseInt(_currentPage);
int pageSize = Integer.parseInt(_pageSize);
//.获取查询条件对象
BufferedReader br=req.getReader();
String params = br.readLine();
//转为Brand对象
Brand brand = JSON.parseObject(params, Brand.class);
PageBean<Brand> pageBean = brandService.selectByPageAndCondition(currentPage, pageSize,brand);
//.将集合转化为json,序列化数据
String string = JSON.toJSONString(pageBean);
//.响应数据,数据带中文所以要设置 response.setContentType("text/json;charset=utf-8");
resp.setContentType("text/json;charset=utf-8");
resp.getWriter().write(string);
}

前端

image-20220419154934288

更改了seletAll代码

get->post

image-20220419155139094

并且传入了输入的brand对象

前端代码优化

主要是js中方法中使用this要用参数引用,这一点很不方便

var _this=this

我们可以使用箭头函数,比如下面我们的selectAll方法就可以改成

selectAll(){
axios({
method:"post",
url:"http://localhost:8080/cookie-demo/brand/selectByPageAndCondition?currentPage="+this.currentPage+"&pageSize="+this.pageSize,
data:this.brand
}).then(resp=>{
this.tableData= resp.data.rows;
this.totalCount=resp.data.totalCount;
})
},
posted @   Ember00  阅读(125)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
点击右上角即可分享
微信分享提示