文章目录
- 前言
- 数据库
- 后端代码
- util 代码
- listener 代码
- filter 代码
- po 代码
- dao 层增删改查代码
- service 层增删改查代码
- controller 层增删改查代码
- 前端代码
- 查询操作
- 删除功能
- 增加功能
- 修改方法
- 路由传参修改
- 会话存储修改
前言
提示:这里可以添加本文要记录的大概内容:
req(request)
:请求
resp(response)
:响应
请求通常是指客户端发送给服务器的请求消息。该请求可以包含请求方法、URL、HTTP版本、请求头和请求体等信息。服务器端会接收到这个请求,进行处理后再返回相应的响应消息。
响应通常是指服务器返回给客户端的响应消息。该响应可以包含HTTP状态码、响应头和响应体等信息。客户端会接收到这个响应并进行处理,例如渲染网页、下载文件等。
在Java中,开发者可以使用一些框架或库来处理请求和响应,例如Servlet API或Spring MVC等。这些框架和库提供了丰富的API和工具来处理网络通信、请求路由、数据转换和异常处理等。
提示:以下是本篇文章正文内容,下面案例可供参考
前端向后端发请求,后端controller接到请求后request.getParameter()
取出数据,数据多的话封装到 po中,封装完后 service 处理请求,处理过程中设计数据库调用 dao,dao处理完后有结果了,结果给 service ,再给 controller,controller 根据结果再生成响应给前端
数据库
数据库代码:
drop TABLE IF EXISTS food;
-- IF EXISTS 表名; 作用:如果表存在就删掉(这段代码怎么执行都不会报错)
CREATE TABLE food
(
foodId int auto_increment PRIMARY KEY,
foodName VARCHAR(20) NOT NULL,
foodPrice DOUBLE(8,2) NOT NULL,
details VARCHAR(255), -- 菜品描述
think VARCHAR(255) -- 菜品评价
);
INSERT INTO food(foodName,foodPrice,details,think)
VALUES('年糕',30.00,'多吃一块,幸福满满','还行,好吃不贵');
后端代码
新建Javaweb动态项目
项目包目录:
util 代码
util :封装了JDBC代码的工具类
注意里面的数据库名和密码
package com.project.mvc.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class JdbcUtil {
public static Connection createConnection() {
Connection connection = null;
try {
connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/food?characterEncoding=utf8&serverTimezone=Asia/Shanghai", "root", "123456");
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
//释放资源 封装到静态方法中
public static void close(Statement statement,Connection connection) {
try {
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void close(ResultSet resultSet,Statement statement,Connection connection) {
try {
resultSet.close();
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//String类型转换为java.sql.Date类型 封装到方法中
public static java.sql.Date toSqlDate(String string){
java.util.Date d1=null;
java.sql.Date d2=null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
d1 = sdf.parse(string);
d2 = new java.sql.Date( d1.getTime() );
} catch (ParseException e) {
e.printStackTrace();
}
return d2;
}
}
listener 代码
listener:放监听器
package com.project.mvc.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class WebServerListener implements ServletContextListener{
@Override
public void contextInitialized(ServletContextEvent sce) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
filter 代码
filter:放过滤器
package com.project.mvc.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebFilter("/*")
public class CommonFilter implements Filter{
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
// 设置请求的编码方式 post方式请求需要
req.setCharacterEncoding("utf8");
// 设置响应内容类型及编码方式
resp.setContentType("application/json;charset=utf8");
// 设置响应头允许ajax跨域请求
resp.setHeader("Access-Control-Allow-Origin", "*");
// 放行
chain.doFilter(request, response);
}
}
po 代码
po:放简单对象
public class Food {
private Integer foodId;
private String foodName;
private double foodPrice;
private String details;
private String think;
// Getter/Setter/to String/有参无参构造方法自动生成
}
dao 层增删改查代码
dao:数据访问 JDBC
增删改返回结果是整数
package com.project.mvc.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import com.project.mvc.po.Food;
import com.project.mvc.util.JdbcUtil;
public class FoodDao {
// 插入菜品信息 做封装
public int insertFood(Food food) {
// 定义返回值,默认值0
int result = 0;
// 只有插入需要结果集ResultSet
Connection connection = null;
PreparedStatement statement = null;
// 创建数据库连接
connection = JdbcUtil.createConnection();
try {
// 创建预编译的 SQL 语句并设置参数,id在数据库中是自增这里不需要写
statement = connection.prepareStatement("insert into food(foodName,foodPrice,details,think) values(?,?,?,?)");
// 给? 赋值,用setXXX方法
statement.setString(1, food.getFoodName());
statement.setDouble(2, food.getFoodPrice());
statement.setString(3, food.getDetails());
statement.setString(4, food.getThink());
// 执行 SQL语句,返回结果,增删改用executeUpdate()方法,都属于更新
result = statement.executeUpdate();
} catch (SQLException e) {
// TODO try/catch 包围
e.printStackTrace();
} finally {
// 关闭数据库连接和预编译的语句
JdbcUtil.close(statement, connection);
}
// 返回结果
return result;
}
// 删除指定菜品信息 按照主键删除
public int deleteFoodId(int foodId) {
// 定义结果,默认值0
int result = 0;
Connection connection = null;
PreparedStatement statement = null;
// 创建数据库连接
connection = JdbcUtil.createConnection();
try {
// 创建预编译的 SQL 语句并设置参数
statement = connection.prepareStatement("delete from food where foodId=?");
// 这个方法里面没有封装数据
statement.setInt(1, foodId);
// 执行 SQL语句,返回成功操作的结果,增删改都属于更新
result = statement.executeUpdate();
} catch (SQLException e) {
// TODO try/catch 块
e.printStackTrace();
} finally {
// 关闭数据库连接和预编译的语句
JdbcUtil.close(statement, connection);
}
// 返回结果
return result;
}
// 修改菜品信息
public int UpdateFood(Food food) {
// 定义返回值
int result = 0;
Connection connection = null;
PreparedStatement statement = null;
// 创建数据库连接
connection = JdbcUtil.createConnection();
try {
// 创建预编译的 SQL 语句(根据主键改其他列)并设置参数
statement = connection.prepareStatement("update food set foodName=?,foodPrice=?,details=?,think=? where foodId=?");
// 给? 赋值,用setXXX方法
statement.setString(1,food.getFoodName());
statement.setDouble(2,food.getFoodPrice());
statement.setString(3,food.getDetails());
statement.setString(4,food.getThink());
statement.setInt(5,food.getFoodId());
// 执行 SQL语句,返回结果
result = statement.executeUpdate();
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} finally {
// 关闭数据库连接和预编译的语句
JdbcUtil.close(statement, connection);
}
// 返回的结果
return result;
}
// 模糊查询菜品 返回一个集合
public ArrayList<Food> query(String foodName){
// 定义返回值
ArrayList<Food> list = new ArrayList<>();
// 查询需要结果集
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
// 创建数据库连接
connection = JdbcUtil.createConnection();
try {
// 创建预编译的 SQL 语句并设置参数
statement = connection.prepareStatement("select foodId,foodName,foodPrice,details,think from food where foodName like ?");
// 设置名字模糊查询 给?赋值
statement.setString(1,"%"+foodName+"%");
// 执行 SQL 语句,结果是个结果集resultSet
resultSet = statement.executeQuery();
// 带条件的while循环,有下一个取出来
while (resultSet.next()) {
// 创建出一个Food对象
Food food = new Food();
// 把结果集的数据取出来,进行Set
food.setFoodId(resultSet.getInt("foodId"));
food.setFoodName(resultSet.getString("foodName"));
food.setFoodPrice(resultSet.getDouble("foodPrice"));
food.setDetails(resultSet.getString("details"));
food.setThink(resultSet.getString("think"));
// 将 Food 对象添加至查询结果列表
list.add(food);
}
} catch (SQLException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} finally {
// 关闭数据库连接、查询结果和预编译的语句
JdbcUtil.close(resultSet, statement, connection);
}
// 返回查询结果列表
return list;
}
}
service 层增删改查代码
dao 的调用者是 service,service 被 controller调用
service:业务逻辑类代码
下面代码用了一个三元运算符,可以将它解释为如下代码:
if (dao.insertFood(food) > 0) {
return "食品增加成功";
} else {
return "食品增加失败";
}
三元运算符的格式为:条件表达式 ? 表达式 1 : 表达式 2
。
其中条件表达式的值为 true
,则返回表达式 1 的值,否则返回表达式 2 的值。
因此当调用 insertFood
方法插入食品记录成功时,三元运算符的条件表达式值为 true
,则返回 “食品增加成功”,否则返回 “食品增加失败”
package com.project.mvc.service;
import java.util.ArrayList;
import com.google.gson.Gson;
import com.project.mvc.dao.FoodDao;
import com.project.mvc.po.Food;
// 业务类调用 dao 类方法
public class FoodService {
// 调用dao,提前创建dao对象
private FoodDao dao = new FoodDao();
// 定义 add 方法,返回字符串,参数是po类
public String add(Food food) {
// dao层返回值 是 整数 > 0 ?(是否)成功 : (否则)失败
return dao.insertFood(food) > 0 ? "食品增加成功" : "食品增加失败";
}
// 定义 remove 方法,返回整数
public String remove(int foodId) {
// 调用 FoodDao 类的 deleteFoodId 方法,并返回操作结果
return dao.deleteFoodId(foodId) > 0 ? "食品删除成功" : "食品删除失败";
}
// 定义 update 方法,返回字符串,参数是po类
public String update(Food food) {
// 调用 FoodDao 类的 UpdateFood 方法,并返回操作结果
return dao.UpdateFood(food) > 0 ? "食品修改成功" : "食品修改失败";
}
// 定义 query 方法,返回 Gson格式字符串(按照名字模糊查询,传一个名字进来)
public String query(String foodName) {
// 调用 FoodDao 类的 query 方法,拿到返回的集合
ArrayList<Food> list = dao.query(foodName);
// 创建 Gson 对象
Gson gson = new Gson();
// 将查询结果转化为 JSON 格式并返回
return gson.toJson(list);
}
}
controller 层增删改查代码
controller:放 servlet 代码,业务逻辑类
先测试后端:
package com.project.mvc.controller;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// 加WebServlet注解,设置servlet的访问路径
@WebServlet("/food")
// 继承HttpServlet
public class FoodController extends HttpServlet {
// 重写servlet的 service方法
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取 请求 发来的数据
String action = req.getParameter("action");
// 获取 响应
PrintWriter writer = resp.getWriter();
// 根据请求参数中的action值进行不同的处理
if (action.equals("add")) {
// 生成响应 输出
writer.print("添加请求处理完毕");
} else if (action.equals("delete")) {
// 生成响应 输出
writer.print("删除请求处理完毕");
} else if (action.equals("update")) {
// 生成响应 输出
writer.print("更新请求处理完毕");
} else if (action.equals("query")) {
// 生成响应 输出
writer.print("查找请求处理完毕");
}
}
}
postman测试:测试前运行 Tomcat 服务器
经过测试所有请求均处理完毕
在真实项目中,并不是直接生成响应,要在里面写各自真正处理的代码
在这里每写一个功能就测试一下
package com.project.mvc.controller;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.project.mvc.po.Food;
import com.project.mvc.service.FoodService;
@WebServlet("/food")
public class FoodController extends HttpServlet {
// 创建一个FoodService的实例,用于调用其中的方法
private FoodService service = new FoodService();
// 重写HttpServlet中的service方法
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 获取 前端请求 发来的数据
String action = req.getParameter("action");
// 获取 响应
PrintWriter writer = resp.getWriter();
// 判断请求的类型添加
if (action.equals("add")) {
// 获取请求参数,传过来的数据都是字符串
String foodName = req.getParameter("foodName");
String foodPrice = req.getParameter("foodPrice");
String details = req.getParameter("details");
String think = req.getParameter("think");
// 创建一个Food对象,用 po对象封装
Food food = new Food();
// 调用setXXX方法封装
food.setFoodName(foodName);
// 取出来的数据是字符串,这里的数据是double,所以这里需要转型
food.setFoodPrice(Double.parseDouble(foodPrice));
food.setDetails(details);
food.setThink(think);
// 调用service处理,在上面创建,方面后面调用
// 调用FoodService中的add()方法,将数据添加到数据库中
String result = service.add(food);
// 将结果输出到前端页面
writer.print(result);
// 删除数据
} else if (action.equals("delete")) {
// 获取请求参数,类型是String
String foodId = req.getParameter("foodId");
// 调用FoodService中的remove()方法,将数据从数据库中删除
String result = service.remove(Integer.parseInt(foodId));
// 将结果输出到前端页面
writer.print(result);
// 更新数据
} else if (action.equals("update")) {
// 获取请求参数
String foodId = req.getParameter("foodId");
String foodName = req.getParameter("foodName");
String foodPrice = req.getParameter("foodPrice");
String details = req.getParameter("details");
String think = req.getParameter("think");
// 创建一个Food对象,用于存储数据(封装)
Food food = new Food();
// 将获取到的参数存储到Food对象中
food.setFoodId(Integer.parseInt(foodId));
food.setFoodName(foodName);
food.setFoodPrice(Double.parseDouble(foodPrice));
food.setDetails(details);
food.setThink(think);
// 调用FoodService中的update()方法,更新数据到数据库中
String result = service.update(food);
// 将结果输出到前端页面
writer.print(result);
// 是查询数据
} else if (action.equals("query")) {
// 获取请求参数,查name数据即可
String foodName = req.getParameter("foodName");
// 返回值 调用FoodService中的query()方法,从数据库中查询数据
String result = service.query(foodName);
// 将结果输出到前端页面
writer.print(result);
}
}
}
各个功能测试:
添加测试:
删除测试:
修改测试:
查询测试:
总结
前端通过视图发送来一些数据,controller
负责接受请求,接到请求后取出请求发来的数据,数据多的话就把数据封装到po
里;接下来调用业务类service
,数据多的话把po
传给service
去用;service
需要去调dao
,数据多的话也传po
请求来了→controller→数据多的话就数据封装po→service→dao→service→controller→生成响应给前端
前端代码
新建一个前端项目,在创建时勾选上Router选项,因为有跳转
创建好项目后安装axios
和qs
框架
最后生成内容框、左侧框与上方框
<template>
<div class="wrapper">
<header class="header">外卖系统</header>
<div class="main">
<aside class="menu">
<router-link to="/query">外卖管理</router-link>
</aside>
<section class="work">
<router-view></router-view>
</section>
</div>
</div>
</template>
然后随便生成点样式区分
然后生成三个视图FoodAdd
、FoodQuery
、FoodUpdate
接下来在index.js
文件中导入这三个路由并配置路由对象
import FoodAdd from '@/views/FoodAdd'
import FoodQuery from '@/views/FoodQuery'
import FoodUpdate from '@/views/FoodUpdate'
const routes = [
{
path: '/query',
name: 'query',
component: FoodQuery
},
{
path: '/add',
name: 'add',
component: FoodAdd
},
{
path: '/update',
name: 'update',
component: FoodUpdate
}
]
查询操作
<template>
<div>
菜品名:<input type="text" v-model="foodName">
<button @click="query">查询</button>
<button @click="gotoAdd">新增</button>
<table>
<tr>
<th>菜品编号</th>
<th>菜品名</th>
<th>菜品价格</th>
<th>菜品描述</th>
<th>菜品评价</th>
<th>修改</th>
<th>删除</th>
</tr>
<tr v-for="(food, index) in items" :key="index">
<!-- 与po类中属性名一致 -->
<th>{{ food.foodId }}</th>
<th>{{ food.foodName }}</th>
<th>{{ food.foodPrice }}</th>
<th>{{ food.details }}</th>
<th>{{ food.think }}</th>
<th><button @click="gotoUpdate(index)">修改</button></th>
<th><button @click="del(index)">删除</button></th>
</tr>
</table>
</div>
</template>
<script>
import axios from 'axios'
import qs from 'qs'
export default {
data () {
return {
}
},
methods: {
},
components: {},
computed: {},
watch: {},
mounted () {}
}
</script>
<style scoped>
/* 加点样式 */
</style>
接下来在data
中配置查询相关数据(双向绑定的数据:foodName
,遍历的数据:items
)
data () {
return {
foodName: '',
items: []
}
},
接下来在methods
发请求:
methods: {
query(){
}
}
然后需要引入的axios
框架发请求给后端(在script
标签下)
import axios from 'axios'
接下来就可以在query
方法内对请求进行发送
query(){
axios.get(`http://localhost:8888/MVCProject/food?action=query&foodName=${this.foodName}`)
.then((response)=>{
// response:返回来的响应,也可以写成resp
this.items = response.data
})
},
路径在postman内找:
其中菜品名字的值要变成动态的
点击查询后:
删除功能
删除是发送post请求,正常发送数据需要导入qs
框架(在script
标签下)
import qs from 'qs'
接下来要把菜品编号发给服务器
// i:下标
del(i){
alert(this.items[i].foodId)
}
这时候点击删除按钮会有对应的下边提示
删除要传两个参,第一个是地址,第二个是post发送的数据
del(i){
// alert(this.items[i].foodId)
axios.post('http://localhost:8888/MVCProject/food',qs.stringify({
action: 'delete',
foodId: this.items[i].foodId
})).then((response)=>{
alert(response.data)
// 查询删完后的结果
this.query()
})
}
增加功能
方法名:gotoAdd
gotoAdd(){
// 不需要传参,直接加地址
this.$router.push('/add')
}
接下来回到Add视图加一些输入框
这里的数据是跟controller
类中的取数据的名字一致
v-model是绑定到一个对象里的几个属性
<template>
<div>
菜品名称:<input type="text" v-model="food.foodName"> <br>
菜品价格:<input type="text" v-model="food.foodPrice"> <br>
菜品描述:<input type="text" v-model="food.details"> <br>
菜品评价:<input type="text" v-model="food.think"> <br>
<button @click="addFood">新增</button>
</div>
</template>
接下来写data
data () {
return {
// 对象用{}
food: {
foodName: '',
foodPrice: '',
details: '',
think: '',
}
}
},
接下来在methods
内编写addFood
方法
先导入ajax请求导入axios
框架,因为要发数据,所以也导入qs
框架
import axios from 'axios'
import qs from 'qs'
methods
内:
methods: {
addFood(){
// v-model是绑定到food对象里的几个属性 简化
axios.post('http://localhost:8888/MVCProject/food',qs.stringify(this.food))
}
},
但是现在还少个action
,所以在food对象中加一个action数据
data () {
return {
// 对象用{}
food: {
foodName: '',
foodPrice: '',
details: '',
think: '',
action: 'add'
}
}
},
随后完善addFood
方法
methods: {
addFood(){
// v-model是绑定到food对象里的几个属性 简化
axios.post('http://localhost:8888/MVCProject/food',qs.stringify(this.food))
.then( (response)=>{
// 增加弹窗
alert(response.data)
} )
}
},
修改方法
路由传参修改
在FoodQuery页面中已经定义过了gotoUpdate
方法,所有在下面加上gotoUpdate方法
gotoUpdate(i){
this.$router.push({
path: '/update',
// query方式传参
query: this.items[i]
})
}
在修改页面中先把template写完:
在修改页面中要有ID,但是只能看,不能改(只读):readonly
<template>
<div>
菜品编号:<input type="text" readonly v-model="food.foodId"> <br>
菜品名称:<input type="text" v-model="food.foodName"> <br>
菜品价格:<input type="text" v-model="food.foodPrice"> <br>
菜品描述:<input type="text" v-model="food.details"> <br>
菜品评价:<input type="text" v-model="food.think"> <br>
<button @click="updateStudent">修改</button>
</div>
</template>
接下来写脚本部分:
1、定义绑定的对象 food
2、完成updateFood方法的编写
data () {
return {
food: {
foodId: this.$route.query.foodId,
foodName: this.$route.query.foodName,
foodPrice: this.$route.query.foodPrice,
details: this.$route.query.details,
think: this.$route.query.think,
action: 'update'
}
}
},
点击修改按钮,看一下数据有没有传过来
接下来要做修改的提交
在script
标签下先导入
import axios from 'axios';
import qs from 'qs';
随后发请求,处理响应(.then
)
methods: {
updateFood(){
axios.post('http://localhost:8888/MVCProject/food',qs.stringify(this.food))
.then((response)=>{
alert(response.data)
})
}
},
会话存储修改
把FoodUpdate页面复制一份取名FoodUpdateSession
加以区分
然后在index.js中导入路由并配置路由对象
import FoodUpdateSession from '@/views/FoodUpdateSession'
//...
{
path: '/session',
name: 'session',
component: FoodUpdateSession
}
接下来在FoodQuery页面的修改按钮中再加一个修改按钮:
<th><button @click="gotoUpdate(index)">路由传参</button><button @click="gotoSession(index)">会话存储</button></th>
在下面加上gotoSession方法
gotoSession(i){
this.$router.push('/session')
}
先看下能不能跳过去
现在还没有数据,接下来存数据
gotoSession(i){
sessionStorage.setItem('food',JSON.stringify(this.items[i]))
this.$router.push('/session')
}
随后再运行一遍,打开开发者工具查看应用→会话存储
接下来取出数据恢复对象形式
在FoodUpdateSession
视图下删除data中的数据,变成:
data () {
return {
food: {
}
}
},
属性需要在会话中取出来,用到了钩子函数mounted
需要在上个视图中,存储在会话里的数据取出来
mounted () {
let s = sessionStorage.getItem('food')
s = JSON.parse(s)
this.food = s
}
这时候数据就传过来了
现在还差个action
就可以修改了,但是在发送前需要action
,在发送前增加新的属性action
methods: {
updateFood(){
this.food['action'] = 'update'
axios.post('http://localhost:8888/MVCProject/food',qs.stringify(this.food))
.then((response)=>{
alert(response.data)
})
}
},