JavaWeb项目实战——品牌后台管理系统

  • 项目概述
    • 功能介绍
    • 成果展示
  • 项目实现
    • 使用Maven构建项目
      • Maven介绍
      • 具体操作
    • 使用Mybatis封装对数据库的操作
      • 在Mysql中建表,并添加数据
      • 在pojo包下创建JavaBean
      • 在pom.xml中添加依赖
      • 配置mybatis.xml
      • 配置BrandMapper.xml以及BrandMapper
      • 测试mapper方法
    • 服务器端配置及代码编写
      • 为项目配置tomcat
      • 编写service层代码
      • 编写web层代码
    • 搭建前端页面
      • 前端技术介绍
      • brand页面代码实现

项目概述

本次项目在传统javaweb项目基础上,使用了Maven来构建整个项目,前端使用Vue框架以及Element组件库,并且使用MyBatis作为持久层框架。通过以上技术,大大提高了开发效率。

通过实现以上功能,加深自己对JavaWeb的认识,同时加强自己对Vue,Maven,Axios,MyBatis,Servlet等相关技术的掌握。

功能介绍

本次的项目是一个品牌后台管理系统,其功能包括:

  • 显示所有品牌信息
  • 修改品牌信息
  • 删除品牌信息
  • 添加品牌信息
  • 批量删除品牌信息
  • 显示分页
  • 模糊查询

成果展示

项目实现

通过以下步骤,逐步完成本次项目所需实现的功能。

使用Maven构建项目

Maven介绍

Maven:Maven是专门用于管理和构建java项目的工具,主要功能如下:

  1. 标准化的项目结构
  2. 标准化的构建结构
  3. 依赖管理

使用Maven构建项目的最大的好处是导包非常方便。在配置好Maven后,使用Maven构建项目的操作流程如下:

具体操作

第一步,在新建项目后选择Maven,为项目确定好名称后点击Finish,完成项目的创建。

第二步,右击项目,选择Add Frameworks Support,为项目添加web框架。

第三步,由于web项目需要打包成war包,而maven默认打包方式为jar包,因此需要在pom.xml中设置打包方式为war包。在maven的pom.xml文件中加入如下代码

<packaging>war</packaging>

第四步,在java目录下创建名为com.itheima的包,在itheima目录下,创建mapper,pojo,service,utils,web包。

至此便完成了使用Maven对项目的构建,项目的目录结构如下:

由于IDEA版本原因,项目结构可能存在不同,我的web相关目录(带蓝点的)的目录名可能是web后续运行时,蓝点突然会消失,后续需要在
Facets中设置。(建议在创建maven项目时,直接使用web骨架)

修复后的项目目录如下:

使用Mybatis封装对数据库的操作

MyBatis:MyBatis是一款持久层框架,可以简化JDBC开发。
主要解决JDBC存在的以下问题:

  1. 硬编码
  2. 操作繁琐

使用MyBatis操作数据库的流程如下:

在Mysql中建表,并添加数据

在mysql数据库中创建相应的表,并添加一些数据。

drop table if exists tb_brand;
-- 创建tb_brand表
create table tb_brand
(-- id 主键id           int primary key auto_increment,-- 品牌名称brand_name   varchar(20),-- 企业名称company_name varchar(20),-- 排序字段ordered      int,-- 描述信息description  varchar(100),-- 状态:0:禁用  1:启用status       int
);
-- 添加数据
insert into tb_brand (brand_name, company_name, ordered, description, status)
values ('华为', '华为技术有限公司', 100, '万物互联', 1),('小米', '小米科技有限公司', 50, 'are you ok', 1),('格力', '格力电器股份有限公司', 30, '让世界爱上中国造', 1),('阿里巴巴', '阿里巴巴集团控股有限公司', 10, '买买买', 1),('腾讯', '腾讯计算机系统有限公司', 50, '玩玩玩', 0) ;SELECT * FROM tb_brand;

在pojo包下创建JavaBean

根据数据库中品牌表的结构创建描述表的类,需要注意的是类中的属性,不能用基本数据类型来修饰,必须用包装类。因为有些时候包装类的对象的属性可能为null,而基本数据类型不能为null,否则会报错。Brand.java的代码如下:

package com.itheima.pojo;public class Brand {// id 主键private Integer id;// 品牌名称private String brandName;// 企业名称private String companyName;// 排序字段private Integer ordered;// 描述信息private String description;// 状态:0:禁用 1:启用private Integer status;@Overridepublic String toString() {return "Brand{" +"id=" + id +", brandName='" + brandName + '\'' +", companyName='" + companyName + '\'' +", ordered=" + ordered +", description='" + description + '\'' +", status=" + status +'}';}//逻辑视图 该方法在后续的前端展示中将用文字代替0 1 nullpublic String getStatusStr(){if (status == null){return "未知";}return status == 0 ? "禁用":"启用";}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getBrandName() {return brandName;}public void setBrandName(String brandName) {this.brandName = brandName;}public String getCompanyName() {return companyName;}public void setCompanyName(String companyName) {this.companyName = companyName;}public Integer getOrdered() {return ordered;}public void setOrdered(Integer ordered) {this.ordered = ordered;}public String getDescription() {return description;}public void setDescription(String description) {this.description = description;}public Integer getStatus() {return status;}public void setStatus(Integer status) {this.status = status;}
}

在pom.xml中添加依赖

在pom.xml添加mybatis,jdbc,junit的依赖,具体操作的可以百度以"maven jdbc"这样的格式搜索,通常不会有问题。或者使用alt+enter 搜索相应包名导入。

<dependencies><!--        mybatis依赖--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.5</version></dependency><!--        mysql驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.29</version></dependency><!--        junit单元测试--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency><!--        servlet--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><!--        fastjson--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.66</version></dependency></dependencies>

配置mybatis.xml

在resources目录下配置mybatis的xml文件,取名为mybatis-config.xml,内容模板在mybatis中文网的入门部分,mybatis-config.xml的代码如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><typeAliases><package name="com.itheima.pojo"/></typeAliases><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql:///mybatis?useSSL=false&amp;allowPublicKeyRetrieval=true"/><property name="username" value="账号"/><property name="password" value="密码"/></dataSource></environment></environments><mappers>
<!--        <mapper resource="com/itheima/mapper/UserMapper.xml"/>-->
<!--        包扫描,通过以下代码,将该目录下的文件全都导入--><package name="com.itheima.mapper"/></mappers>
</configuration>

xml代码中有两点在官网给的模板上做出了优化。

第一点:添加了typeAliases标签,并使用了包扫描的方式。这样做的好处是使用类名的小写作为类的别名,减少类完全限定名的冗余。

第二点,使用包扫描的方式方式来配置标签mappers中的内容,好处是减少代码量。

在这一步,有以下地方需要注意。在配置数据库url时,由于mysql版本问题,为了成功连接数据库并能顺利执行sql语句,需要携带两个参数,关键代码如下:
<property name="url" value="jdbc:mysql:///mybatis?useSSL=false&amp;allowPublicKeyRetrieval=true"/>
此外在mybatis-config.xml中可以配置多个数据库连接,具体想使用哪个数据库就让environments 中的default等于environment的id。
<environments default="development"> <environment id="development">

配置BrandMapper.xml以及BrandMapper

在开始配置之前,在IDEA的settings的plugins中下载MybatisX,可以提高配置效率(目录出现Mybatis图标表明插件成功下载并使用)。

在mybatis中,BrandMapper.xml是用来写sql语句,mapper是用来申明方法的,并且要求xml文件和java文件必须在同一目录下才能发挥作用。由于使用了maven,所有的xml文件都会被放置在resources目录中,在经过编译后,resources目录下的内容会和java目录下的内容都会出现在同一个目录下。因此,可以在resources目录下创建子目录用来放BrandMapper.xml。其目录结构与BrandMapper的包的结构相同。如图:

在创建完以上两个文件后,接着在BrandMapper接口中申明所需的方法,方法和我们项目要实现的功能相对应。BrandMapper.java的代码如下:

package com.itheima.mapper;import com.itheima.pojo.Brand;
import org.apache.ibatis.annotations.Param;import java.util.List;public interface BrandMapper {//查询所有品牌信息List<Brand> selectAll();//根据id查询品牌信息Brand selectBrandById(int id);//根据条件查询品牌信息List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String companyName, @Param("brandName") String brandName);//根据条件查询品牌信息 参数为BrandList<Brand> selectByConditionSingle(Brand brand);//添加一条品牌信息void add(Brand brand);//更新一条品牌信息void update(Brand brand);//根据id删除一条品牌信息void deleteById(int id);//根据id批量删除品牌信息void deleteByIds(int[] ids);//查询品牌记录总数int selectTotalCount();//分页查询品牌信息List<Brand> selectByPage(@Param("begin") int begin,@Param("size") int size);//根据条件分页查询品牌信息List<Brand> selectByPageAndCondition(@Param("begin") int begin, @Param("size") int size, @Param("brand") Brand brand);//根据条件查询int totalCountByPageAndCondition(Brand brand);
}

通过以上方法,可以完成项目功能的持久层部分。当然,一开始就写这么多方法是比较复杂或者难以想到的,所以可以先申明最简单的增删改查操作。后续再慢慢根据项目所需实现的功能,慢慢补全代码。

由于在前面,我们安装了MyBatisX插件,所以在写完这些方法后,方法名会标红。这时,我们只需要alt+enter即可来到BrandMapper.xml页面来完成方法的具体实现。

首先我们来完成查询所有的具体实现。当我们通过alt+enter来到BrandMapper.xml页面时,MyBatisX已经为我们在页面上生成了部分代码:<select id="selectAll" resultType="com.itheima.pojo.Brand"></select>我们只需要在select标签内书写相应sql即可。

但实际上这里还存在问题。由于pojo类的属性遵循驼峰原则,而tb_brand的字段使用下划线分割。因此记录中像company_name,brand_name这样的字段的值是不能被获取到brand对象中的。

所以我们需要配置resultMap来代替resultType。具体操作如下:

首先,配置resultMap

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

然后将select标签中的resultTyle改成resultMap

    <select id="selectAll" resultMap="brandResultMap">select *from tb_brand;</select>

通过该方法,可以解决取不到company_name,brand_name值的问题。

接着我们完成更新,删除,添加等操作。在像是根据条件查询的sql语句中,由于条件个数不固定,所以我们需要使用动态SQL,在这里先不做过多赘述,直接上BrandMapper.xml的关键代码。

 <!--根据条件分页查询品牌信息--><select id="selectByPageAndCondition" resultMap="brandResultMap">select *from tb_brand<where><if test="brand.status!=null">and status = #{brand.status}</if><if test="brand.companyName!=null and brand.companyName!=''">and company_name like #{brand.companyName}</if><if test="brand.brandName!=null and brand.brandName!='' ">and brand_name like #{brand.brandName}</if></where>limit #{begin},#{size}</select><!--根据id批量删除品牌信息--><delete id="deleteByIds">delete from tb_brandwhere idin<foreach collection="array" item="id" separator="," open="(" close=")">#{id}</foreach></delete>

测试mapper方法

在项目的test目录下创建com.itheima.test包,在test包下创建项目MyBatisTest完成开始测试。MapperTest关键代码如下:

 @Testpublic void selectAllTest() throws IOException {//1,获取sqlSessionFactoryString resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//2.获得sqlSessionSqlSession sqlSession = sqlSessionFactory.openSession();//事务开启//3.通过Mapper代理开发BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);List<Brand> brands = mapper.selectAll();System.out.println(brands);//4.关闭资源sqlSession.close();}

测试完成后,发现所有方法都是可用的,至此我们完成了MyBatis部分配置。

服务器端配置及代码编写

在本次项目中,使用tomcat作为服务器。所有的资源都会被放在tomcat的webapp下。

为项目配置tomcat

在IDEA的edit configurations中配置tomcat local服务器。这一步比较简单,但还有两点需要注意:
第一点,是需要配置tomcat服务器的VM options为-Dfile.encoding=UTF-8。这样做的目的是为了解决在使用tomcat时的控制台乱码问题。
第二点,在Artifact中选择以war的方式配置,而不是以war exploded的方式。因为以war的方式,会将资源都放在tomcat的webapp下,更加符合实际开发。

编写service层代码

service层的作用,主要是调用dao层(mapper包下)的方法完成增删改查操作。通过之前编写完mapper的测试类我们可以知道,mapper中的方法不能直接调用,还需要先获取sqlsessionfactory,sqlseesion…等一系列操作,而service层将会完成这一些列繁琐操作的封装。后续web层,想要执行什么操作,只需要调用service层的对应的方法即可。

正如前面mapper测试类中的代码那样,想要调用mapper类的方法,我们要经过以下操作:

  1. 获取SqlSessionFactory对象
  2. 通过SqlSessionFactory对象,获取SqlSession对象。
  3. 通过SqlSession对象,获取Mapper对象
  4. 通过Mapper对象,执行需要的方法

每一个方法都是这样的步骤,其中会有很多重复的代码。因此我们在之前准备好utils包下,创建与此相关的工具类,SqlSessionFactoryUtils.java的代码如下:

package com.itheima.utils;import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;
import java.io.InputStream;public class SqlSessionFactoryUtils {private static SqlSessionFactory sqlSessionFactory;static {//静态代码块会随着类的加载而自动执行,且只执行一次try {String resource = "mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {e.printStackTrace();}}public static SqlSessionFactory getSqlSessionFactory(){return sqlSessionFactory;}
}

通过以上代码,以后想要获取SqlSessionFactory对象,只需要调用SqlSessionFactoryUtils下的 getSqlSessionFactory()方法即可,提升开发效率。

创建完工具类之后,正式开始service类的编写。首先,我们需要创建一个名为BrandService的接口,并创建名为BrandServiceImp的类来实现接口。
接着在BrandService接口中申明方法,再通过BrandServiceImp依此实现。

为什么需要通过类来实现接口的方式来完成service层的代码编写,主要有两个原因:
一是这样只需要查看接口中申明的方法就能知道所有的方法。
二是为后来spring框架的引入做准备。

以下为BrandService.java的代码:

package com.itheima.service;import com.itheima.pojo.Brand;import java.util.List;public interface BrandService {public List<Brand> selectAll();public void add(Brand brand);public void deleteByIds(int[] ids);public void update(Brand brand);public void deleteById(int id);public List<Brand> selectByPage(int begin,int size);public List<Brand> selectByPageAndCondition(int begin,int size,Brand brand);public int selectTotalCount();public int totalCountByPageAndCondition(Brand brand);
}

以下为BrandServiceImp.java的代码:

package com.itheima.service;import com.itheima.mapper.BrandMapper;
import com.itheima.pojo.Brand;
import com.itheima.utils.SqlSessionFactoryUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;import java.util.List;public class BrandServiceImp implements BrandService{SqlSessionFactory sqlSessionFactory = SqlSessionFactoryUtils.getSqlSessionFactory();@Overridepublic List<Brand> selectAll(){SqlSession sqlSession = sqlSessionFactory.openSession();BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);List<Brand> brands = mapper.selectAll();sqlSession.close();return brands;}@Overridepublic void add(Brand brand) {SqlSession sqlSession = sqlSessionFactory.openSession();BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);mapper.add(brand);sqlSession.commit();sqlSession.close();}@Overridepublic void deleteByIds(int[] ids) {SqlSession sqlSession = sqlSessionFactory.openSession();BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);mapper.deleteByIds(ids);sqlSession.commit();sqlSession.close();}@Overridepublic void update(Brand brand) {SqlSession sqlSession = sqlSessionFactory.openSession();BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);mapper.update(brand);sqlSession.commit();sqlSession.close();}@Overridepublic void deleteById(int id) {SqlSession sqlSession = sqlSessionFactory.openSession();BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);mapper.deleteById(id);sqlSession.commit();sqlSession.close();}@Overridepublic List<Brand> selectByPage(int begin, int size) {SqlSession sqlSession = sqlSessionFactory.openSession();BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);List<Brand> brands = mapper.selectByPage(begin, size);sqlSession.close();return brands;}@Overridepublic List<Brand> selectByPageAndCondition(int begin, int size, Brand brand) {SqlSession sqlSession = sqlSessionFactory.openSession();BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);List<Brand> brands = mapper.selectByPageAndCondition(begin, size, brand);sqlSession.close();return brands;}@Overridepublic int selectTotalCount() {SqlSession sqlSession = sqlSessionFactory.openSession();BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);int count = mapper.selectTotalCount();sqlSession.close();return count;}@Overridepublic int totalCountByPageAndCondition(Brand brand) {SqlSession sqlSession = sqlSessionFactory.openSession();BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);int count = mapper.totalCountByPageAndCondition(brand);sqlSession.close();return count;}}

通过以上代码,service层的代码就全部完成了,如果想要测试代码,可以在测试类中通过new BrandServiceImp对象,并调用其方法完成测试。

编写web层代码

web层主要用来存放web的一些组件,像是servlet、filter、listener等等。在本次项目中只需要使用到servlet。
在使用默认的servlet时,一个servlet对应一个功能,同时使用注释的方式对应一个url。
一个项目往往有很多功能,如果项目比较大型,意味着可能有几十上百个servlet,这样很不好。最好能用一个类对应一个servlet,这样可以减少servlet数量。
我们希望在网址栏中输入http://localhost:8080/类名/方法名的方式即可调用方法。
已知自己所写的servlet是继承HttpServlet的,HttpServlet的service()方法是根据请求方式来分发的。所以我们要重写HttpServlet的service()方法。让它能够实现我们想要的效果。所以我们编写BaseServlet.java的代码,其代码如下:

package com.itheima.web;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class BaseServlet extends HttpServlet {//重写service方法 防止以get或者post方式进行路由@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{//1.获取请求路径String uri = req.getRequestURI();//2.通过字符串截取的方式,确定请求的方法int index = uri.lastIndexOf('/');String methodName = uri.substring(index + 1);//3.通过反射的方式,将方法名所对应的方法运行//子类继承BaseServlet后,this.getClass()将会获取子类的Class对象Class<? extends BaseServlet> aClass = this.getClass();try {Method method = aClass.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);//2.3 执行方法method.invoke(this,req,resp);} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}}

通过继承BaseServlet,我们在网址栏中输入以方法名结尾的url即可调用当前Servlet的相对应的方法。接着我们再编写BrandServlet的代码,BrandServlet.java的代码如下:

package com.itheima.web;import com.alibaba.fastjson.JSON;
import com.itheima.pojo.Brand;
import com.itheima.service.BrandService;
import com.itheima.service.BrandServiceImp;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.List;@WebServlet("/brand/*")
public class BrandServlet extends BaseServlet {BrandService brandService = new BrandServiceImp();public void selectAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1.调用service层查询所有的brand,返回一个ListList<Brand> brands = brandService.selectAll();//2.将得到的list结果转化为JSONString brandsStr = JSON.toJSONString(brands);//3.为response设置返回的格式,并将值返回response.setContentType("text/json;charset=UTF-8");response.getWriter().write(brandsStr);}public void addBrand(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{//1. 接收品牌数据BufferedReader br = request.getReader();String params = br.readLine();//json字符串
//        System.out.println(params);//转为Brand对象Brand brand = JSON.parseObject(params, Brand.class);//3. 调用service添加brandService.add(brand);//4.若添加成功,则向前端写回successresponse.getWriter().write("success");}public void deleteByIds(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{//1.接收前端发送的idsBufferedReader br = request.getReader();String params = br.readLine();////2.将json转化为数组int[] ids = JSON.parseObject(params, int[].class);//3.调用service的批量删除操作brandService.deleteByIds(ids);//若删除成功,则向前端写回successresponse.getWriter().write("success");}public void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{//1.接收前端发送的json格式数据BufferedReader br = request.getReader();String params = br.readLine();//2.将json格式数据转化为brand对象Brand brand = JSON.parseObject(params, Brand.class);//3.调用service的更新功能brandService.update(brand);//4.若更新成功则向前端写回successresponse.getWriter().write("success");}public void deleteById(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{//1.接收前端发送的IdString params = request.getParameter("id");//2.将得到的id从String格式转化为int格式int id = Integer.parseInt(params);//调用service的删除功能brandService.deleteById(id);//4.若删除成功,则向前端写回successresponse.getWriter().write("success");}public void selectTotalCount(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{//将总页数写回前端int count = brandService.selectTotalCount();String countStr = String.valueOf(count);response.getWriter().write(countStr);}public void selectByPage(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{//获取前端的两个参数,当前页数,每页显示记录条数String page = request.getParameter("currentPage");String size = request.getParameter("pageSize");int currentPage = Integer.parseInt(page);int pageSize = Integer.parseInt(size);//通过当前页数以及显示每页的记录条数返回listList<Brand> brands = brandService.selectByPage(pageSize*(currentPage-1), pageSize);//将list转化为json格式写回前端String brandJson = JSON.toJSONString(brands);response.setContentType("text/json;charset=UTF-8");response.getWriter().write(brandJson);}public void selectByPageAndCondition(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{//1.获取请求的页数以及单页记录数String page = request.getParameter("currentPage");String size = request.getParameter("pageSize");int currentPage = Integer.parseInt(page);int pageSize = Integer.parseInt(size);//2.获取请求的条件,并从JSON格式转化为对象BufferedReader br = request.getReader();String brandJson = br.readLine();Brand brand = JSON.parseObject(brandJson, Brand.class);//3.将前端发送的数据进行处理if (brand!=null) {String brandName = brand.getBrandName();String companyName = brand.getCompanyName();if (brandName!=null && brandName!=""){brandName="%"+brandName+"%";}if (companyName!=null && companyName!=""){companyName="%"+companyName+"%";}brand.setBrandName(brandName);brand.setCompanyName(companyName);}List<Brand> brands = brandService.selectByPageAndCondition(pageSize * (currentPage - 1), pageSize, brand);//将查询到的对象转化为JSON格式,并设定返回格式为uft-8的json然后写回String brandsJson = JSON.toJSONString(brands);response.setContentType("text/json;charset=utf-8");response.getWriter().write(brandsJson);}public void totalCountByPageAndCondition(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{BufferedReader br = request.getReader();String brandJson = br.readLine();Brand brand = JSON.parseObject(brandJson, Brand.class);if (brand!=null) {String brandName = brand.getBrandName();String companyName = brand.getCompanyName();if (brandName!=null && brandName!=""){brandName="%"+brandName+"%";}if (companyName!=null && companyName!=""){companyName="%"+companyName+"%";}brand.setBrandName(brandName);brand.setCompanyName(companyName);}int count = brandService.totalCountByPageAndCondition(brand);String countStr = String.valueOf(count);response.getWriter().write(countStr);}
}

通过编写以上代码,我们可以在浏览器输入http://localhost:8080/javaweb_demo/brand/addBrand的方式调用BrandServlet的addBrand方法。

此处,在编写Servlet代码时,涉及到获取前端数据,这里有一点需要注意。
前端传递数据的方式分为get和post,其中post方式得到的数据是json格式。request.getParameter("xxx")是获取不到的。必须使用BufferedReader br = request.getReader();String params = br.readLine();//json字符串

此外,在编写servlet要充分考虑前端发送的数据类型与参数名称。有些时候,前端发送的数据得用两种方式获取。

至此,完成了所有后端代码的编写。

搭建前端页面

前端的技术涉及到Ajax ,Vue,Element技术。

前端技术介绍

Ajax 作用有以下两方面:

  1. 与服务器进行数据交换:通过AJAX可以给服务器发送请求,服务器将数据直接响应回给浏览器。
  2. 异步交互:可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术。

Axios 对原生的AJAX进行封装,简化书写。
以下是使用Axios完成向服务器发送异步请求的简单案例:

 axios({method:"get",url:"http://localhost:8080/pro_maven/brand/selectAll",}).then(function (resp) {console.log(resp.data);})

Vue 是一套前端框架,免除原生JavaScript中的DOM操作,简化书写。
Vue 基于MVVM(Model-View-ViewModel)思想,实现数据的双向绑定,将编程的关注点放在数据上。
在使用Vue之前,需要导入它的js文件。<script src="js/vue.js"></script>
接着在html页面中创建Vue对象,并修改视图即可。以下是一个例子

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="js/vue.js"></script>
</head>
<body><div id="app"><input v-model="username"><!--插值表达式-->{{username}}</div>
</body>
<script>//1. 创建Vue核心对象new Vue({el:"#app",data(){ // data() 是 ECMAScript 6 版本的新的写法return {username:""}}});
</script>
</html>

Element:是饿了么公司前端开发团队提供的一套基于 Vue 的网站组件库,用于快速构建网页。
Element 提供了很多组件(组成网页的部件)供我们使用。例如 超链接、按钮、图片、表格等等。
想要使用Element的组件,只需要复制官网的组件的代码即可。

brand页面代码实现

项目的前端代码brand.html内如如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>brand</title><script src="js/vue.js"></script><script src="element-ui/lib/index.js"></script><script src="js/axios-0.18.0.js"></script><link rel="stylesheet" href="element-ui/lib/theme-chalk/index.css"></link>
</head>
<body><div id="app"><!--搜索表单--><el-form :inline="true" :model="brand" class="demo-form-inline"><el-form-item label="当前状态"><el-select v-model="brand.status" placeholder="当前状态"><el-option label="启用" value="1"></el-option><el-option label="禁用" value="0"></el-option></el-select></el-form-item><el-form-item label="企业名称"><el-input v-model="brand.companyName" placeholder="企业名称"></el-input></el-form-item><el-form-item label="品牌名称"><el-input v-model="brand.brandName" placeholder="品牌名称"></el-input></el-form-item><el-form-item><el-button type="primary" @click="selectByPageAndCondition">查询</el-button></el-form-item></el-form><!--按钮--><el-row><el-button type="danger" plain @click="deleteByIds">批量删除</el-button><el-button type="primary" plain @click="dialogVisible = true">新增</el-button></el-row><!--修改数据对话框表单--><el-dialogtitle="修改品牌":visible.sync="dialogVisible1"width="30%"><el-form ref="form" :model="brand" label-width="80px"><el-form-item label="品牌名称"><el-input v-model="brand.brandName"></el-input></el-form-item><el-form-item label="企业名称"><el-input v-model="brand.companyName"></el-input></el-form-item><el-form-item label="排序"><el-input v-model="brand.ordered"></el-input></el-form-item><el-form-item label="备注"><el-input type="textarea" v-model="brand.description"></el-input></el-form-item><el-form-item label="状态"><el-switch v-model="brand.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="clearBrand">取消</el-button></el-form-item></el-form></el-dialog><!--添加数据对话框表单--><el-dialogtitle="新增品牌":visible.sync="dialogVisible"width="30%"><el-form ref="form" :model="brand" label-width="80px"><el-form-item label="品牌名称"><el-input v-model="brand.brandName"></el-input></el-form-item><el-form-item label="企业名称"><el-input v-model="brand.companyName"></el-input></el-form-item><el-form-item label="排序"><el-input v-model="brand.ordered"></el-input></el-form-item><el-form-item label="备注"><el-input type="textarea" v-model="brand.description"></el-input></el-form-item><el-form-item label="状态"><el-switch v-model="brand.status"active-value="1"inactive-value="0"></el-switch></el-form-item><el-form-item><el-button type="primary" @click="addBrand">提交</el-button><el-button @click="dialogVisible = false">取消</el-button></el-form-item></el-form></el-dialog><!--表格--><template><el-table:data="tableData"style="width: 100%":row-class-name="tableRowClassName"@selection-change="handleSelectionChange"><!--选项框--><el-table-columntype="selection"width="55"></el-table-column><!--序列号--><el-table-columntype="index"width="50"></el-table-column><el-table-columnprop="brandName"label="品牌名称"align="center"width="180"></el-table-column><el-table-columnprop="companyName"label="企业名称"align="center"width="180"></el-table-column><el-table-columnprop="ordered"align="center"label="排序"></el-table-column><el-table-columnprop="statusStr"align="center"label="当前状态"></el-table-column><el-table-columnalign="center"label="操作"><template slot-scope="scope"><el-row><el-button type="primary"  @click="update(scope.row)" type="text" size="small">修改</el-button><el-button type="danger" @click="deleteById(scope.row.id)" type="text" size="small">删除</el-button></el-row></template></el-table-column></el-table></template><!--分页工具条--><el-pagination@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="currentPage":page-sizes="[5, 10, 15, 20]":page-size="pageSize"layout="total, sizes, prev, pager, next, jumper":total="rowCount"></el-pagination>
</div>
<script>new Vue({el:"#app",data() {return {rowCount:"",currentPage: 1,pageSize:5,dialogVisible: false,dialogVisible1: false,multipleSelection: [],selectedIds:[],brand: {status: '',brandName: '',companyName: '',id: "",ordered: "",description: ""},tableData: [{brandName: '华为',companyName: '华为科技有限公司',ordered: '100',status: "1"}]}},methods:{selectByPageAndCondition(){var _this = thisaxios({method:"post",url:"http://localhost:8080/pro_maven/brand/selectByPageAndCondition?currentPage="+this.currentPage+"&pageSize="+this.pageSize,data:this.brand}).then(function (resp){_this.tableData=resp.data;_this.totalCountByPageAndCondition();})},handleSizeChange(val) {console.log(`每页 ${val} 条`);this.currentPage=1;this.pageSize=val;this.selectByPageAndCondition();},handleCurrentChange(val) {console.log(`当前页: ${val}`);this.currentPage=val;this.selectByPageAndCondition();},update(row){this.dialogVisible1 = true;this.brand=row},updateBrand(){var _this = this;axios({method:"post",url:"http://localhost:8080/pro_maven/brand/update",data:_this.brand}).then(function (resp){if (resp.data=="success"){_this.$message({message: '恭喜你,修改成功',type: 'success'});}_this.dialogVisible1 =false;_this.selectByPageAndCondition();_this.clearBrand();})},deleteById(id){// console.log(id);this.$confirm('此操作将删除该数据, 是否继续?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() =>{var _this=this;axios({url:"http://localhost:8080/pro_maven/brand/deleteById?id="+id,method:"get"}).then(function (resp){if (resp.data=="success"){_this.$message({message: '恭喜你,删除成功',type: 'success'});_this.selectByPageAndCondition();}})}).catch(() => {//用户点击取消按钮this.$message({type: 'info',message: '已取消删除'});});},handleSelectionChange(val) {this.multipleSelection = val;// console.log(this.multipleSelection)},deleteByIds(){this.$confirm('此操作将删除该数据, 是否继续?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() =>{for (let i = 0; i < this.multipleSelection.length; i++) {let selectionElement = this.multipleSelection[i];this.selectedIds[i] = selectionElement.id;}var _this=this;axios({url:"http://localhost:8080/pro_maven/brand/deleteByIds",method:"post",data:this.selectedIds}).then(function (resp){if(resp.data=="success"){_this.$message({message: '恭喜你,删除成功',type: 'success'});_this.selectByPageAndCondition();}})}).catch(() => {//用户点击取消按钮this.$message({type: 'info',message: '已取消删除'});});},clearBrand(){this.brand.id="";this.brand.brandName='';this.brand.status= '';this.brand.brandName= '';this.brand.companyName= '';this.brand.ordered= "";this.brand.description= "";this.dialogVisible1 = false;this.selectByPageAndCondition();},addBrand() {// console.log(this.brand);var _this = this;// 发送ajax请求,添加数据axios({method:"post",url:"http://localhost:8080/pro_maven/brand/addBrand",data:_this.brand}).then(function (resp) {if(resp.data == "success"){//添加成功//关闭窗口_this.dialogVisible = false;// 重新查询数据_this.selectByPageAndCondition();// 弹出消息提示_this.$message({message: '恭喜你,添加成功',type: 'success'});_this.clearBrand()}})},selectByPage(){var _this = this;axios({method:"get",url:"http://localhost:8080/pro_maven/brand/selectByPage?currentPage="+this.currentPage+"&pageSize="+this.pageSize}).then(function (resp){_this.tableData=resp.data;})},totalCount(){var _this = this;axios({method:"get",url:"http://localhost:8080/pro_maven/brand/selectTotalCount"}).then(function (resp){_this.rowCount = resp.data;// console.log(_this.pageSize)// console.log(_this.currentPage)})},totalCountByPageAndCondition(){var _this = this;axios({url:"http://localhost:8080/pro_maven/brand/totalCountByPageAndCondition",method:"post",data:this.brand,}).then(function (resp){_this.rowCount = resp.data;})},selectAll(){var _this = this;axios({method:"get",url:"http://localhost:8080/pro_maven/brand/selectAll",}).then(function (resp) {_this.tableData = resp.data;})}},mounted(){this.selectByPageAndCondition();}})
</script>
</body>
</html>

这里的前端代码写的比较乱还没有经过优化,后续可以通过优化使得前端代码更加简洁美观。

【JavaWeb】JavaWeb项目实战——品牌后台管理系统相关推荐

  1. 基于javaweb的宠物商城带后台管理系统(java+ssm+jsp+jquery+ajax+mysql)

    基于javaweb的宠物商城带后台管理系统(java+ssm+jsp+jquery+ajax+mysql) 运行环境 Java≥8.MySQL≥5.7.Tomcat≥8 开发工具 eclipse/id ...

  2. Vue 2.x 实战之后台管理系统开发(二)

    1. 导语 承接上文:Vue 2.x 实战之后台管理系统开发(一) 在上一篇文章中,我详细叙述了如何创建项目框架和引入各种后台常用插件,做好这些准备工作后,我们就可以着手进行页面的开发了.在开发过程中 ...

  3. 视频教程-vuecli实战商城后台管理系统-Vue

    vuecli实战商城后台管理系统 帝莎学院创始人&CEO,目前主要从事全栈开发.Python.PHP.小程序.App.Web等技术的研究和开发.专注于实战类教程,授课风趣幽默,讲解条理清晰.通 ...

  4. Asp.Net Core 项目实战之权限管理系统(0) 无中生有

    0 Asp.Net Core 项目实战之权限管理系统(0) 无中生有 1 Asp.Net Core 项目实战之权限管理系统(1) 使用AdminLTE搭建前端 2 Asp.Net Core 项目实战之 ...

  5. VUE全家桶项目实战-- 4.后台首页布局

    VUE全家桶项目实战-- 4.后台首页布局 一.页面布局 二.创建Home组件 三.路由index.js 文件配置主页路径 四.添加welcome组件 一.页面布局 <el-container& ...

  6. Thinkphp实战教程后台管理系统开发

    目录 ├─Thinkphp5 后台管理开发.png ├─Thinkphp5 后台管理开发.xmind ├─Thinkphp实战教程后台管理系统开发-1.课程介绍及大纲.mp4 ├─Thinkphp实战 ...

  7. 基于mybatis-jsp-bootstrap-servlet-mysql-maven的Javaweb课程设计--刷题后台管理系统(考试题目管理系统)

    第一章 需求分析 计算机技术没有应用到考试上时,组织一次考试只是要经过五步:人工出题,考生考试,人工阅卷,成绩评估和试卷分析,这是一项十分繁琐和容易出错的工作,教师的工作量非常的大.很明显,传统的考试 ...

  8. 最新Spring Boot实战项目(权限后台管理系统)详解

    Spring Boot实战项目 - 权限后台管理系统 简介 这是一套基于spring boot 2.16.shiro.jwt.redis.swagger2.mybatis .thymeleaf.lay ...

  9. Java EE Web开发与项目实战_【手把手】JavaWeb 入门级项目实战 -- 文章发布系统 (第一节)...

    312334546574820.jpg 序 前一段时间有很多朋友来问我各种问题,比如java怎么学,c,c++,c#,java,还有php等等,到底学哪个好,哪个好就业?其中不乏刚毕业找不到工作的学生 ...

最新文章

  1. 推荐一个学习golang的地址
  2. make编译过程-Android10.0编译系统(三)
  3. c 语言链表的另一种实现
  4. 删除隐藏版本信息 版本回退_Qt如何给程序添加版本信息
  5. python学习-38迭代器和生成器
  6. 可是来个拦路虎的scutzh
  7. 老将回归,英特尔的复兴之路
  8. Mac 下更新 .bash_profile 文件
  9. 怎么在不重启tomcat服务器的情况下更新修改过的后台代码,修改类不用重启Tomcat加载整个项目...
  10. 正则表达式匹配以xx开头以xx结尾
  11. EDP to LVDS转换设计电路|EDP to LVDS转接板电路|Capstone/CS5211芯片电路原理图参考
  12. 多校2.1012La Vie en rose
  13. 游戏的初级体验,三围:视、听、触的展示
  14. ggplot2_coor_xxx()坐标系变换
  15. 女人是这样哄的,学以致用
  16. Unity游戏配置存储方案
  17. mac 微信备份到外接硬盘方案(软链接)
  18. 工作中使用到的单词(软件开发)_20210317_备份
  19. [设计分析]3-1 v0.1 教学辅助——点名册外观详细设计
  20. UESTC 1265

热门文章

  1. java“漫画之家”系统springbootvueweb
  2. 【68】JS(4)——表达式和语句②流程控制语句(1)条件分支语句
  3. mac 使用origin绘制多个数据误差棒 (叠加图层的方法)
  4. python的class类调用和封装思想
  5. B. A Perfectly Balanced String? 思维 vector小技巧
  6. 六个国外免费DNS服务-做英文与外贸网站必备工具
  7. QQ群78928780记录整理:90518人生话题-部分
  8. 联想E14 开机黑屏报错2102:Detection error on HDD0 (Main HDD)
  9. react class组件对组件传入props属性限制和默认值
  10. 想让行车记录仪协助道路病害自动化检测?可以!