前后端交互
1.创建axios.js文件
//1.导入axios import axios from 'axios' //2.创建axios对象 let instance = axios.create({ //指定公共的请求前缀,暂时不需要上下文,使用/代替 baseURL:"http://localhost:8080/", timeout:5000 }) //3.添加拦截器 instance.interceptors.request.use( config = () =>{ return config }, error = () =>{ return Promise.reject(error) } ) instance.interceptors.response.use( response =() => { return response }, error = () =>{ return Promise.reject(error) } ) //4.默认导出js export default instance
向服务器发起请求
import axios from './requset/axios' onMounted( () => { //页面加载完成之后 调用该函数 ajaxGet() }) //向服务器发送Ajax get请求 并且需要携带参数 let ajaxGet = async () => { let params = {id:100,name:"jerry"} let {data} = await axios.get("user/getMsg",{params}) console.log(data) }
2.搭建后端框架
2.1创建pojo实体类
package com.liu.pojo; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data @NoArgsConstructor @AllArgsConstructor public class User implements Serializable { private Integer id; private String name; private Integer age; private String sex; }
2.2创建userdao接口以及userdaoImpl实现类
2.3添加BaseDaoImpl ,
创建util包,添加JDBCUtil和MD5Util,
JDBCTools package com.liu.util; import com.alibaba.druid.pool.DruidDataSourceFactory; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; /* * 获取连接或释放连接的工具类 */ public class JDBCTools { // 1、创建数据源,即连接池 private static DataSource dataSource; // 2、创建ThreadLocal对象 //作用: 在同一个线程内,实现数据共享,保证数据安全!! 节省内存空间 private static ThreadLocal<Connection> threadLocal; static { try { //1、读取druip.properties文件 Properties pro = new Properties(); pro.load(com.liu.util.JDBCTools.class.getClassLoader().getResourceAsStream("druid.properties")); //2、连接连接池 dataSource = DruidDataSourceFactory.createDataSource(pro); //3、创建线程池 threadLocal = new ThreadLocal<>(); } catch (Exception e) { e.printStackTrace(); } } /** * 获取连接的方法 * * @return * @throws SQLException */ public static Connection getConnection() { // 从线程中获取连接 Connection connection = threadLocal.get(); if (connection == null) { // 从连接池中获取一个连接 try { connection = dataSource.getConnection(); // 将连接与当前线程绑定 threadLocal.set(connection); } catch (SQLException e) { e.printStackTrace(); } } return connection; } /** * 释放连接的方法 * */ public static void releaseConnection() { // 获取当前线程中的连接 Connection connection = threadLocal.get(); if (connection != null) { try { connection.close(); // 将已经关闭的连接从当前线程中移除 threadLocal.remove(); } catch (SQLException e) { e.printStackTrace(); } } } }
package com.liu.util; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public final class MD5Util { public static String encrypt(String strSrc) { try { char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; byte[] bytes = strSrc.getBytes(); MessageDigest md = MessageDigest.getInstance("MD5"); md.update(bytes); bytes = md.digest(); int j = bytes.length; char[] chars = new char[j * 2]; int k = 0; for (int i = 0; i < bytes.length; i++) { byte b = bytes[i]; chars[k++] = hexChars[b >>> 4 & 0xf]; chars[k++] = hexChars[b & 0xf]; } return new String(chars); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); throw new RuntimeException("MD5加密出错"); } } }
创建resources配置文件包,添加druid.properties
#key=value driverClassName=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/top_news?serverTimezone=UTC&rewriteBatchedStatements=true&characterEncoding=utf-8 username=root password=123456 initialSize=20 maxActive=50 maxWait=1000
创建service包,创建UserService接口以及UserServiceImpl实现类
UserServiceImpl
package com.liu.service; import com.liu.dao.Userdao; import com.liu.dao.UserdaoImpl; import com.liu.pojo.User; import java.util.List; public class UserServiceImpl implements UserService{ private Userdao userdao= new UserdaoImpl(); @Override public List<User> findAll() { return userdao.findAll(); } }
创建controller包,添加BaseController
package com.liu.controller; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.lang.reflect.Method; //该Controller是为了抽取共同的Service的方法 不能实例化 public abstract class BaseController extends HttpServlet { /** * 基于反射机制 调用业务方法 */ @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //解决响应乱码问题 //resp.setContentType("text/html;charset=utf-8"); //1.获取用户的业务方法 String requestURI = req.getRequestURI(); //2.获取业务名称 /day07/user/login /login login String methodName = requestURI.substring(requestURI.lastIndexOf("/")+1); //3.获取当前类的类型 Class targetClass = this.getClass(); //4.获取当前类的方法对象 try { Method method = targetClass.getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); //5.开启暴力反射 method.setAccessible(true); //6.调用方法 对象.方法(参数) method.invoke(this, req,resp); } catch (Exception e) { System.out.println("method方法:"+methodName +"调用异常!!!"); e.printStackTrace(); throw new RuntimeException(e); } } protected abstract void getMsg(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException; }
创建UserController,继承BaseController
package com.liu.controller; import com.fasterxml.jackson.databind.ObjectMapper; import com.liu.pojo.User; import com.liu.service.UserService; import com.liu.service.UserServiceImpl; import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; @WebServlet("/user/*") public class UserController extends BaseController{ private UserService userService = new UserServiceImpl(); protected void getMsg(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.接收用户请求参数 String id = req.getParameter("id"); String name = req.getParameter("name"); System.out.println(id+":"+name); //2.查询所有的表中数据 List<User> userList = userService.findAll(); //3.通过层级返回获取到结果,将java对象转换为json字符串 ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(userList); System.out.println(json); //4.响应数据 resp.setContentType("text/html;charset=utf-8"); resp.getWriter().write("服务器响应成功"); } }
3.解决跨域问题
3.1创建Filter包,导入CrosFilter过滤器
package com.liu.filter; import jakarta.servlet.*; import jakarta.servlet.annotation.WebFilter; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; @WebFilter("/*") public class CrosFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT,OPTIONS, DELETE, HEAD"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "access-control-allow-origin, authority, content-type, version-info, X-Requested-With"); // 非预检请求,放行即可,预检请求,则到此结束,不需要放行 if(!request.getMethod().equalsIgnoreCase("OPTIONS")){ filterChain.doFilter(servletRequest, servletResponse); } } }
查询所有的表中数据
UserController private UserService userService = new UserServiceImpl(); //2.查询所有的表中数据 List<User> userList = userService.findAll();
package com.liu.service; import com.liu.pojo.User; import java.util.List; public interface UserService { List<User> findAll(); }
package com.liu.service; import com.liu.dao.Userdao; import com.liu.dao.UserdaoImpl; import com.liu.pojo.User; import java.util.List; public class UserServiceImpl implements UserService { private Userdao userdao= new UserdaoImpl(); @Override public List<User> findAll() { return userdao.findAll(); } }
package com.liu.dao; import com.liu.pojo.User; import java.util.List; public interface Userdao { List<User> findAll(); }
package com.liu.dao; import com.liu.pojo.User; import java.util.List; public class UserdaoImpl extends BaseDaoImpl implements Userdao { @Override public List<User> findAll() { String sql = "select id,name,age,sex from user"; return getList(User.class,sql); } }
4.关于返回值的问题:
Object Mapper 是jackson包下的
将java转化为json字符串
mapper.writeValueAsString(user);
将JSON转化为java对象
mapper.readValue(json,User.class);
//3.通过层级返回获取到结果,将java对象转换为json字符串 ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(userList); System.out.println(json); //4.响应数据 resp.setContentType("text/html;charset=utf-8"); resp.getWriter().write("服务器响应成功"); resp.getWriter().write(json);
5.解决统一数据返回值的问题
导入Result和Enum包装类
package com.liu.common; /** * 全局统一响应的JSON格式处理类 * */ public class Result<T> { // 返回码 private Integer code; // 返回消息 private String message; // 返回数据 private T data; public Result(){} // 返回数据 public static <T> Result<T> build(T data) { Result<T> result = new Result<T>(); if (data != null) result.setData(data); return result; } public static <T> Result<T> build(T body, Integer code, String message) { Result<T> result = build(body); result.setCode(code); result.setMessage(message); return result; } public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) { Result<T> result = build(body); result.setCode(resultCodeEnum.getCode()); result.setMessage(resultCodeEnum.getMessage()); return result; } /** * 操作成功 * @param data baseCategory1List * @param <T> * @return */ public static<T> Result<T> ok(T data){ Result<T> result = build(data); return build(data, ResultCodeEnum.SUCCESS); } public Result<T> message(String msg){ this.setMessage(msg); return this; } public Result<T> code(Integer code){ this.setCode(code); return this; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public T getData() { return data; } public void setData(T data) { this.data = data; } }
package com.liu.common; public enum ResultCodeEnum { SUCCESS(200,"success"), USERNAEM_ERROR(501,"usernameError"), PASSWORD_ERROR(503,"passwordError"), NOTLOGIN(504,"notlogin"), USERNAME_USED(505,"usernameUsed"); private Integer code; private String message; private ResultCodeEnum(Integer code ,String message){ this.code= code; this.message = message; } public Integer getCode() { return code; } public String getMessage() { return message; } }
将userList封装进result中
UserController //4.同一系统返回值 Result result = Result.ok(userList); String json = mapper.writeValueAsString(result);
onMounted( () => { //页面加载完成之后 调用该函数 ajaxGet () }) //向服务器发送Ajax get请求 并且需要携带参数 let ajaxGet = async () => { let params = {id:100,name:"jerry"} let {data} = await axios.get("user/getMsg",{params}) console.log(data) console.log("获取业务的状态码信息"+data.code) console.log("获取业务的提示信息"+data.message) console.log("获取业务数据"+data.data) }
6.将统一json返回值包装成WebUtil类
package com.liu.util; import com.liu.common.Result; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.IOException; import java.text.SimpleDateFormat; public class WebUtil { private static ObjectMapper objectMapper; // 初始化objectMapper static{ objectMapper=new ObjectMapper(); // 设置JSON和Object转换时的时间日期格式 objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")); } // 从请求中获取JSON串并转换为Object public static <T> T readJson(HttpServletRequest request,Class<T> clazz){ T t =null; BufferedReader reader = null; try { reader = request.getReader(); StringBuffer buffer =new StringBuffer(); String line =null; while((line = reader.readLine())!= null){ buffer.append(line); } t= objectMapper.readValue(buffer.toString(),clazz); } catch (IOException e) { throw new RuntimeException(e); } return t; } // 将Result对象转换成JSON串并放入响应对象 public static void writeJson(HttpServletResponse response, Result result){ response.setContentType("application/json;charset=UTF-8"); try { String json = objectMapper.writeValueAsString(result); response.getWriter().write(json); } catch (IOException e) { throw new RuntimeException(e); } } }
UserController //4.同一系统返回值 Result result = Result.ok(userList); //调用WebUtil包装类 实现统一json转化 WebUtil.writeJson(resp,result);
6.post请求参数获取
语法如下:
let postMsg =async () =>{ let user = {id:102,name:"元旦快乐",age:2024,sex:"男"} let {data} = await axios.post("user/postMsg",user) console.log(data) }
该参数是一个JSON字符串和常规的key=value的结构不一样
需要通过请求头的方式动态的获取
public void postMsg(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取请求体的内容 BufferedReader reader = req.getReader(); //读取一行 获取json串 String json = reader.readLine(); ObjectMapper objectMapper = new ObjectMapper(); User user = objectMapper.readValue(json, User.class); System.out.println(user); }
//读取多行,循环遍历 StringBuffer stf = new StringBuffer(); String readLine = null; while (StringUtils.isNullOrEmpty(readLine = reader.readLine())){ //拼接字符串 stf.append(readLine); } //接收所有的json数据 String json = stf.toString(); ObjectMapper objectMapper = new ObjectMapper(); User user = objectMapper.readValue(json, User.class); System.out.println(user); //返回给客户端 WebUtil.writeJson(resp,Result.ok(user));
通过WebUtil类包装
public void postMsg(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { User user = WebUtil.readJson(req, User.class); WebUtil.writeJson(resp,Result.ok(user)); }
7.分页查询
//分页查询 let getUserList = async() =>{ let params = { currentPage:pagination.value.currentPage, pageSize:pagination.value.pageSize, } let {data} = await axios.get("user/findUserListPage") console.log(data) if(data.code === 200){ //业务执行正确 获取服务器返回的业务数据 console.log(data.data) }else{ ElMessage.error("用户获取失败") } }
UserController public void findUserListPage(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.获取分页参数 int currentPage = Integer.parseInt(req.getParameter("currentPage")); int pageSize = Integer.parseInt(req.getParameter("pageSize")); //2.查询分页(页数,条数,总条数,分页后的结果) Map<String,Object> map = userService.findUserListPage(currentPage,pageSize); }
UserServiceImpl public Map<String, Object> findUserListPage(int currentPage, int pageSize) { //1.查询总记录数 long total = userdao.findUserTotal(); Map<String,Object> map = new HashMap<>(); map.put("currentPage",currentPage); map.put("pageSize",pageSize); //total在写完sql语句之后添加 map.put("total",total); return null; }
UserdaoImpl public long findUserTotal() { String sql = "select count(*) from user"; //获取一行一列的结果 return (long) getValue(sql); }
//分页查询结构的参数 int start = (currentPage - 1) * pageSize; List<User> userList = userdao.findUserListPage(start,pageSize); //起始位置和查询的条数start,pageSize
//分页查询语句 @Override public List<User> findUserListPage(int start, int pageSize) { String sql = "select * from user limit ?,?"; return getList(User.class,sql,start,pageSize); }
//返回分页结果 map.put("userList",userList);
//3.将结果响应给客户端 WebUtil.writeJson(resp,Result.ok(map));
获取服务器返回的数据
let {data} = await axios.get("user/findUserListPage",{params}) if(data.code === 200){ //业务执行正确 获取服务器返回的业务数据 let map = data.data pagination.value.currentPage = map.currentPage pagination.value.pageSize = map.pageSize pagination.value.total = map.total tableData.value = map.userList ElMessage.success("分页列表获取成功") }else{ ElMessage.error("用户获取失败") } }
//根据页数跳转 let handleSizeChange = (newSize) => { pagination.value.pageSize = newSize getUserList() } //根据条数跳转 let handleCurrentChange = (newCurrent) => { pagination.value.currentPage = newCurrent getUserList() }
8.全部vue代码
<template> <!-- 1.定义容器 上下结构 --> <el-container> <h1 style="margin: auto;margin-top: 20px;font-size:45px;color:blue">用户管理系统</h1> <el-header> <el-button type="primary" style="margin-top:20px" @click="dialogVisible=true">新增用户</el-button> </el-header> <el-main> <!-- 定义表格 :data="数据的来源 数组类型" prop="date" 数据中的属性 label="Date" 显示字段的名称 stripe: 带斑马纹 border: 带边框线 height="250" 固定表头信息 align="center" 定义对齐方式 居中 --> <el-table :data="tableData" style="width: 100%" stripe border height="300"> <el-table-column prop="id" label="编号" align="center"/> <el-table-column prop="name" label="姓名" align="center"/> <el-table-column prop="age" label="年龄" align="center"/> <el-table-column prop="sex" label="性别" align="center"/> <el-table-column label="操作" align="center"> <template #default="scope"> <el-button type="success" @click="updateUser(scope.row)">修改</el-button> <el-button type="danger" @click="deleteUser(scope.row)">删除</el-button> </template> </el-table-column> </el-table> <!-- 定义分页插件 --> <div class="example-pagination-block" > <!-- 属性介绍 : 1.style="justify-content: center; 水平居中 2.background 分页带背景色 3.layout="prev, pager, next" prev: 左箭头 pager: 页数 next: 右箭头 total: 显示总页数 sizes: 改变每页条数 4.total: 总条数 current-page: 当前页数 page-size: 页面条数 @size-change 页数改变时调用函数 @current-change 手动点击页数时调用 --> <el-pagination :current-page="pagination.currentPage" :page-size="pagination.pageSize" :page-sizes="pagination.pageSizes" layout="total,sizes,prev, pager, next" :total="pagination.total" background @size-change="handleSizeChange" @current-change="handleCurrentChange" style="justify-content: center;"/> </div> <!--添加对话框 dialogVisible对话框是否显示--> <el-dialog v-model="dialogVisible" title="用户新增-修改" width="30%" :before-close="handleClose"> <!--定义表单内容--> <el-form :model="form" :rules="rules" ref="ruleFormRef"> <el-form-item label="ID号:"> <el-input v-model="form.id" disabled/> </el-form-item> <el-form-item label="姓名:" prop="name"> <el-input v-model="form.name" /> </el-form-item> <el-form-item label="年龄:" prop="age"> <el-input v-model.number="form.age" /> </el-form-item> <el-form-item label="性别:" prop="sex"> <el-radio-group v-model="form.sex"> <el-radio label="男" /> <el-radio label="女" /> </el-radio-group> </el-form-item> </el-form> <template #footer> <span class="dialog-footer"> <el-button @click="dialogVisible = false">取消</el-button> <el-button type="primary" @click="updateBtn">提交</el-button> </span> </template> </el-dialog> </el-main> </el-container> </template> <script setup> import {ref,onMounted} from "vue" import axios from './request/axios' import {ElMessage,ElMessageBox} from 'element-plus' const tableData = ref([ { id: 100, name: '安琪拉', age: 20, sex: '男', }, { id: 100, name: '安琪拉', age: 20, sex: '男', }, { id: 100, name: '安琪拉', age: 20, sex: '男', } ]) //定义分页对象 let pagination = ref({ currentPage: 1, pageSize: 5, pageSizes: [5,10,20,40], total: 500 }) //定义对话框是否显示 let dialogVisible = ref(false) //定义用户提交的对象 let form = ref({ id:"", name:"", age:"", sex:"" }) //定义表单校验的规则 let rules = { name: [ { required: true, message: '请输入姓名', trigger: 'blur' }, { min: 2, max: 10, message: '字符串长度2-10', trigger: 'blur' }, ], age: [ { required: true, message: '请输入年龄' }, { type:"number", message: '年龄必须是数字' }, ], sex: [ { required: true, message: '请选择性别' }, ] } //定义表单对象 let ruleFormRef = ref(null) let handleSizeChange = (newSize) => { pagination.value.pageSize = newSize getUserList() } let handleCurrentChange = (newCurrent) => { pagination.value.currentPage = newCurrent getUserList() } //页面加载时调用 onMounted( () => { //页面加载完成之后 调用该函数 getUserList() }) //向服务器发送Ajax get请求 并且需要携带参数 //查询所有的用户列表数据 //分页查询 let getUserList = async() =>{ let params = { currentPage:pagination.value.currentPage, pageSize:pagination.value.pageSize, } let {data} = await axios.get("user/findUserListPage",{params}) if(data.code === 200){ //业务执行正确 获取服务器返回的业务数据 let map = data.data pagination.value.currentPage = map.currentPage pagination.value.pageSize = map.pageSize pagination.value.total = map.total tableData.value = map.userList ElMessage.success("分页列表获取成功") }else{ ElMessage.error("用户获取失败") } } //实现用户新增的操作 let updateBtn = async() =>{ //如果用户填写正确,返回true,否则报错提示 let flag = await ruleFormRef.value.validate() if(flag){ let id = form.value.id if(id){ userUpdate() }else{ userInsert() } } } let updateUser = (user) =>{ //显示对话框 dialogVisible.value=true form.value = user } let userInsert = async() =>{ //发起ajax请求 let {data} = await axios.post("user/insertUser",form.value) if(data.code === 200){ //关闭对话框 dialogVisible.value=false getUserList() //清空对话框 ruleFormRef.value.resetFields() ElMessage.success("新增用户成功") }else{ ElMessage.error("新增用户失败") } } let userUpdate =async () =>{ let {data} = await axios.post("user/updateUser",form.value) if(data.code === 200){ //关闭对话框 dialogVisible.value=false getUserList() //清空对话框 ruleFormRef.value.resetFields() ElMessage.success("修改用户成功") }else{ ElMessage.error("修改用户失败") } } let handleClose = () =>{ ruleFormRef.value.resetFields() dialogVisible.value=false } let deleteUser = async(user) =>{ let flag = await ElMessageBox.confirm( '是否确定删除?', '警告', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', } ) if(flag === 'confirm'){ let {data} = await axios.get("user/deleteUser?id="+user.id) if(data.code === 200){ ElMessage.success("删除用户成功") getUserList() }else{ ElMessage.error("删除用户失败") } } } </script> <style scoped> .example-pagination-block{ margin-top: 20px; margin-bottom: 16px; } </style>