前后端其实都是之前基于黑马程序员Javaweb课程的项目内容,前端用的是vue+element,后端由于期末的学校课程javaweb大作业要求不能使用框架,故将此项目所有mybatis部分改为jdbc的内容,这次小项目包含登陆注册功能和对brand表的增删改查和分页这些操作。
完整的后端项目结构:
DbConfig:存放数据库连接信息
DbUtil:简单对connect和statement进行基础封装和资源的释放(基本都是用static,优点是后面可以直接调用,缺点是无法并发)
package com.itheima.util;
import com.itheima.config.DbConfig;
import java.sql.*;
public class DbUtil {
public static Connection conn = null;
public static Statement stmt = null;
public static ResultSet rs = null;
public static PreparedStatement ptst = null;
public static void connect() {
try {
Class.forName("com.mysql.jdbc.Driver");
DbUtil.conn = DriverManager.getConnection(DbConfig.url, DbConfig.user, DbConfig.password);
} catch (Exception e) {
throw new RuntimeException("数据库连接失败");
}
}
public static void getStmt(){
try {
DbUtil.connect();
DbUtil.stmt = DbUtil.conn.createStatement();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void closeAll() {
if (rs != null)
try {
rs.close();
} catch (SQLException e) {
}
if (stmt != null)
try {
stmt.close();
} catch (SQLException e) {
}
if (ptst != null)
try {
ptst.close();
} catch (SQLException e) {
}
if (conn != null)
try {
conn.close();
} catch (SQLException e) {
}
}
}
CharacterEnco'dingFilter:设置请求和响应的编码格式
Pojo:两个实体类中都封装了拿到数据后封装到所需要往service层传的对象中的方法。
Controller:根据请求路径进行方法的分配
BaseServlet:代替HttpServlet,根据请求的最后一段路径进行方法的分配
package com.itheima.controller;
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;
/**
* 代替HttpServlet,根据请求的最后一段路径进行方法的分配
*/
public class BaseServlet extends HttpServlet {
//根据请求路径进行方法的分配
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取请求路径 拿selectAll来举例:/brand-case/brand/selectAll
String uri = req.getRequestURI();
//2.获取最后一段路径的方法名
int index = uri.lastIndexOf('/');
String methodName = uri.substring(index + 1);//uri.substring所截出来的字符串是/selectAll所以要加一
//3.执行方法
//3.1.获取对应Servlet的字节码对象.class文件
Class<? extends BaseServlet> cls = this.getClass();//这里的this指的是上面继承的BrandServlet对象
//3.2.获取方法Method对象
try {
Method method = cls.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
//3.3.执行方法
method.invoke(this,req,resp);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
关于其他BrandServlet和UserServlet其他详细内容都跟黑马教的差不多,service层也是,不过很多判空操作多了对""的判空,切记不要忘记。
重点讲讲几个重要的dao层方法:
updateById:使用StringBuffer对每一段不为空的所需修改的属性进行拼接,并且提供一个list接收判断不为空的数据,在后面遍历list为sql设置属性,以及提供一个布尔值,判断是否为第一个set属性若不为第一个则拼接字符串时加上逗号。
@Override
public Boolean updateById(Brand brand, Integer id) {
DbUtil.connect();
boolean flag = false;
StringBuffer sql = new StringBuffer();
sql.append("update tb_brand set ");
ArrayList<String> list = new ArrayList<>();
if (brand.getBrandName() != null && !("".equals(brand.getBrandName()))){
sql.append("brand_name = ? ");
list.add(brand.getBrandName());
flag = true;
}
if (brand.getCompanyName() != null && !("".equals(brand.getCompanyName()))){
if (flag){
sql.append(", company_name = ? ");
list.add(brand.getCompanyName());
}else {
sql.append("company_name = ? ");
list.add(brand.getCompanyName());
flag = true;
}
}
if (brand.getOrdered() != null && !("".equals(brand.getOrdered()))){
if (flag){
sql.append(", ordered = ? ");
list.add(brand.getOrdered().toString());
}else {
sql.append("ordered = ?");
list.add(brand.getOrdered().toString());
flag = true;
}
}
if (brand.getDescription() != null && !("".equals(brand.getDescription()))){
if (flag){
sql.append(", description = ? ");
list.add(brand.getDescription());
}else{
sql.append("description = ? ");
list.add(brand.getDescription());
flag = true;
}
}
if (brand.getStatus() != null){
if (flag){
sql.append(", status = ? ");
list.add(brand.getStatus().toString());
}else {
sql.append("status = ?");
list.add(brand.getStatus().toString());
}
}
sql.append("where id = ? ");
list.add(id.toString());
try {
DbUtil.ptst = DbUtil.conn.prepareStatement(sql.toString());
for (int i = 1; i <= list.size(); i++) {
DbUtil.ptst.setString(i, list.get(i-1));
}
System.out.println(DbUtil.ptst.toString());
return DbUtil.ptst.executeUpdate() == 1;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
deleteByIds:因为是批量删除功能,所以要用到jdbc里面的批处理。
addBatch():批量出路sql语句(即将若干sql装载到一起,一起性传往数据库)
executeBatch():对数据做批量更新需要用到
@Override
public void deleteByIds(Integer[] ids) {
String sql = "delete from tb_brand where id=?";
DbUtil.connect();
try {
DbUtil.ptst = DbUtil.conn.prepareStatement(sql);
for (Integer id : ids) {
DbUtil.ptst.setInt(1, id);
DbUtil.ptst.addBatch();
}
int[] result = DbUtil.ptst.executeBatch();
for (int i:result) {
System.out.println(i);
}
} catch (SQLException e) {
e.printStackTrace();
//return false;
}finally {
DbUtil.closeAll();
}
}
selectByPageAndCondition:条件分页查询,也是跟前面update方法相似,采用StringBuffer进行字符串的拼接,注意where的位置存放很有讲究,也是需要用布尔值去判断是否为第一个条件,由前面传来两个分页的条件不能转为string存放到list里面后面遍历取出,Limit后面必须跟的是数字,在这里由于sql语句不合格,找了好久的错误(最后发现preparedStatement能够打印才得以解决)。
selectByPageAndCondition代码如下
@Override
public List<Brand> selectByPageAndCondition(int begin, int size, Brand brand) {
//System.out.println("controller is running....");
DbUtil.connect();
StringBuffer sql = new StringBuffer();
sql.append("select * from tb_brand ");
boolean flag = false;
List<Brand> brands =null;
List<String> list = new ArrayList<>();
if (brand.getBrandName() != null && !("".equals(brand.getBrandName()))) {
sql.append("where brand_name like ? ");
list.add(brand.getBrandName());
flag = true;
}
if (brand.getCompanyName() != null && !("".equals(brand.getCompanyName()))) {
if (flag){
sql.append("and company_name like ? ");
list.add(brand.getCompanyName());
}else {
sql.append("where company_name like ? ");
list.add(brand.getCompanyName());
flag = true;
}
}
if (brand.getStatus() != null) {
if (flag){
System.out.println("4");
sql.append("and status = ? ");
}else{
System.out.println("5");
sql.append("where status = ? ");
}
list.add(brand.getStatus().toString());
}
sql.append("limit ?,?");
//list.add(String.valueOf(begin));
//list.add(String.valueOf(size));
System.out.println(sql);
System.out.println(list);
try {
DbUtil.ptst = DbUtil.conn.prepareStatement(sql.toString());
for (int i = 1; i <= list.size(); i++) {
DbUtil.ptst.setString(i, list.get(i - 1));
}
DbUtil.ptst.setInt(list.size() + 1,begin);
DbUtil.ptst.setInt(list.size() + 2,size);
System.out.println(DbUtil.ptst.toString());
DbUtil.rs = DbUtil.ptst.executeQuery();
brands = Brand.getBrands(DbUtil.rs);
//System.out.println(brands);
return brands;
} catch (SQLException e) {
e.printStackTrace();
return null;
}finally {
DbUtil.closeAll();
}
}
页面:
本次项目总结:花了四个晚上的时间,将原本mybatis项目改为jdbc,原本以为不是一件什么困难的事情,但是实际实现的过程没有想象中那么简单,还是需要养成好习惯写完一层测试一层,前端的vue的使用还不是很熟悉,自己发送一些axious请求也会在接收方式和所需要的数据获取上卡壳,前端的技术还有待加强和提高,后台的基础也不能放过,学过了不等于学会了,还是需要虚心实践以及实现更多的需求。