目录
项目成果
商品后端维护功能
前端功能
数据库表
?项目效果图
项目的收获
WEBAPP开发总体思想
前端开发
后端开发
后端代码的分层作用
前端开发
首页核心代码
添加商品页面核心代码
商品维护页面核心代码
后端开发
数据库工具类
实体
DAO层
Service层
Controller层
PHP项目运行遇到的坑
文章初衷就是学习PHP开发后端项目的过程,推荐一个模块一个模块做,项目代码有没有放文末,这是个随机事件:) ,如果觉得文章不错麻烦动动小手指点个赞吧哈哈。
项目成果
商品后端维护功能
- 添加商品(需要有商品图片,在服务器保存)
- 商品的上架(status字段的取值为“新增”“已上架”“已下架”)
- 商品的基本信息修改(状态为已上架商品不能修改)
- 商品的删除(状态为已上架商品不能删除)
前端功能
- 商品列表页面
- 添加商品页面
- 商品维护页面
数据库表
? ? ? ?商品Product(主键ID,商品名称Name,图片Pic,价格Price,状态Status)? ??
?项目效果图
商品列表首页?
添加商品页面
商品维护页面
?前端好麻烦,这里偷懒了。。。
项目的收获
- 熟悉PHP开发后端的流程
- 熟悉前后端数据交互的流程
- 后端连接数据库和增删改查的流程
- 前端如何把本地图片上传并实时显示
- 上传图片到服务器的流程
WEBAPP开发总体思想
WEBAPP就是网页应用(WEB application)
前端开发
????????负责渲染网页、编写Ajax传输请求数据与获得响应数据。
后端开发
????????负责与服务器的数据库打交道(DAO层)、业务逻辑(Service层)、编写响应前端的方法(Controller层)。
????????一开始没经验开发小项目中代码分层就会让我觉得很麻烦很愚蠢,写了很多没必要的代码。
后端代码的分层作用
????????使我们的项目工程化,而在大项目中代码量很多这个时候我们的大脑就容易混乱注意力不集中,分层就能很好集中我们的注意力开发特定的模块,使项目开发有规律可循并稳定前进。
????????在计算机网络、操作系统、计算机组成原理这些知识体系中分层思想出现较为频繁。
前端开发
网页样式使用BootStrap框架的样式,使得前端页面开发变得简单高效,我代码部分就不贴出引用部分了。
首页核心代码
这里HTML部分我就简单贴出body
<body>
<h1>你好,世界!</h1>
<p class="addBlock"><a href="addGoods.html" class="btn btn-primary addBtn" role="button">添加商品</a></p>
<!-- 商品列表容器 -->
<div class="row">
</div>
</body>
JS部分使商品模块渲染的关键,这里是发送请求到后端,后端响应商品数据回来的ajax。
window.onload = function () {
var rowDiv = document.getElementsByClassName('row')[0];
//请求获得商品数据,并渲染页面
$.ajax({
url:'../controller/GoodsController.php',
type:'POST',
data:'Action=queryAllGoods',
dataType: 'json',
// processData: false,
// contentType: false,
success: function (response) {
console.log(response);
var htmlstr = '';
var status = ["已下架","已上架","新增"];
for(var i = 0; i < response.length; i++){
var goods = response[i];
var lable;
if(goods.status == 0) lable = "label label-default";
else if(goods.status == 1) lable = "label label-success";
else if(goods.status == 2) lable = "label label-danger";
// console.log(goods.status);
htmlstr = "<div id=\"goods"+goods.id+"\" class=\"col-xs-6 col-md-2 \">\n" +
" <div class=\"thumbnail \">\n" +
" <span class=\"goodsStatus "+ lable+"\">"+ status[goods.status]+ "</span>\n" +
" <img src=\""+goods.pic+"\" class=\"goodsImg\">\n" +
" <span class=\"goodsPrice label label-info\">¥"+ goods.price+ "</span>\n" +
"\n" +
" <div class=\"caption\">\n" +
" <h3 class=\"goodsName\">"+ goods.name+ "</h3>\n" +
" <p class=\"goodsDetail\">"+goods.detail+ "</p>\n" +
" <p><a href=\"updateGoods.html?id="+goods.id+"\" class=\"btn btn-primary\" role=\"button\">商品维护</a> <a onclick=\"delGoods("+goods.id+","+goods.status+")\" class=\"btn btn-default\" role=\"button\">删除商品</a></p>\n" +
" </div>\n" +
" </div>\n" +
" </div>";
rowDiv.innerHTML += htmlstr;
}
},
error: function (jqXHR, textStatus, errorMessage) {
console.log(errorMessage); // Optional
}
});
};
响应js的后端代码(大概看过一下,具体在后面)
$Action = '';
//当有post请求到这个php时可以使用$_POST取出请求信息
if(isset($_POST['Action'])){
$Action = $_POST['Action'];
}
if($Action == 'queryAllGoods'){//获得所有商品信息
$goodsService = new GoodsService();
echo $goodsService->getAllGoods();
}
添加商品页面核心代码
HTML结构,CSS自己写写吧。。
<body>
<div class="container">
<p class="returnBtn"><a href="index.html" class="btn btn-primary" role="button">返回</a></p>
<div class="leftDiv">
<!-- <form> -->
<li class="list-group-item list-group-item-info">商品名称</li>
<div class="panel panel-info">
<input id="goodsName" type="text" class="form-control" aria-describedby="basic-addon1">
</div>
<li class="list-group-item list-group-item-info">商品价格</li>
<div class="panel panel-info">
<input id="goodsPrice" type="text" class="form-control" placeholder="输入数字" onkeyup="value=value.replace(/[^\d{1,}]/g,'')" aria-describedby="basic-addon1">
</div>
<li class="list-group-item list-group-item-info">商品状态</li>
<div class="panel panel-info">
<!-- <input type="number" class="form-control" placeholder="0已下架 1已上架 2新增" min="0" max="2" aria-describedby="basic-addon1"> -->
<select id="goodsStatus" class="form-control">
<option value="0">已下架</option>
<option value="1">已上架</option>
<option value="2">新增</option>
</select>
</div>
<li class="list-group-item list-group-item-info">商品基本信息</li>
<div class="panel panel-info">
<input id="goodsDetail" type="text" class="form-control" aria-describedby="basic-addon1">
</div>
<button class="btn btn-primary subBtn" onclick="addGoods()">添加商品</button>
<!-- </form> -->
</div>
<div class="rightDiv">
<img id="goodsImg" src="./img/default.jpg" class="goodsImg">
<div align="center">
<span class="btn btn-success fileinput-button">
<span>上传商品图片</span>
<input type="file" name="pic" id="pic" onchange="showImg()" accept="image/gif, image/jpeg, .png">
</span>
</div>
</div>
</div>
</body>
JS部分,这个也比较关键,图片上传这个需要多留意,比如,如何将本地图片上传到页面上实时显示,并将图片发送到后端。前端图片上传实时显示传送门
这里是模仿form表单的提交,使用了FormData类,其中AJAX默认关闭数据序列化,这里需要设置processData: false,contentType: false这两个属性就可以开启数据序列化。
function showImg(){
//获取上传文件的信息
var upfile = document.getElementById('pic').files[0];
var goodsimg = document.getElementById('goodsImg');
//在pic的文件里抓取该文件用于显示二进制信息
var sr = window.URL.createObjectURL(upfile);
// alert(sr);
goodsimg.src = sr;
}
function addGoods(){
// var goodsName = document.getElementById('goodsName');
var goodsName = $("#goodsName");
var goodsPrice = $("#goodsPrice");
var goodsStatus = $("#goodsStatus");
var goodsDetail = $('#goodsDetail');
var goodsImg = $('#goodsImg');
var upfile = document.getElementById('pic').files[0];
var formData = new FormData();
if(goodsName.val()==''){
alert('添加失败:请填写商品名称');
return;
} else if(goodsPrice.val()==''){
alert('添加失败:请填写商品价格');
return;
} else if(goodsDetail.val()==''){
alert('添加失败:请填写商品明细');
return;
}
formData.append('Action','addGoods');
formData.append('status',goodsStatus.val());
formData.append('name',goodsName.val());
formData.append('price',goodsPrice.val());
formData.append('detail',goodsDetail.val());
formData.append('upfile',upfile);
$.ajax({
url: "../controller/GoodsController.php",
type: "POST",
data: formData,
dataType: 'json', //返回的数据类型
processData: false,
contentType: false,
success: function (response) {
alert(response);
},
error: function (jqXHR, textStatus, errorMessage) {
console.log(errorMessage); // Optional
}
});
}
商品维护页面核心代码
? ? ? ? 这个就跟添加商品差不多,我就不贴出来了,我这里就只贴出如何或获得首页穿过来的参数,疯狂偷懒。。。
//获得当前页面地址
var url = location.href;
//因为就一个参数这里我偷懒,按=切开字符串
var id = parseInt(url.split('=')[1]);
后端开发
代码逻辑都比较简单,这里代码我就只贴出关键部分,其他的看自己需要补充。
代码贴出顺序是由底向上。
数据库工具类
class DBHelper
{
static function getConnect(){
$conn = mysqli_connect(
"localhost",
"root",
"1234",
"goods_php",//数据库名
8806);//数据库端口
//防止中文乱码
mysqli_query($conn,"set names 'utf8'");
return $conn;
}
}
实体
setter和getter我就不贴出来了,这我用private封装后会
class Goods
{
var $id; //商品id
var $name; //商品名称
var $pic; //商品图片地址
var $price; //商品价格
var $status; //商品状态 0已下架 1已上架 2新增
var $detail;
}
DAO层
主要与本地数据库数据打交道的层,这里我代码就只贴出关键部分
class GoodsDao
{
//添加商品信息
function addGoods($goods){
$Name = $goods->getName();
$Pic = $goods->getPic();
$Price = $goods->getPrice();
$Status = $goods->getStatus();
$Detail = $goods->getDetail();
$conn = DBHelper::getConnect();
$conn->query(
"insert into product(Name,Pic,Price,Status,Detail) values('$Name','$Pic','$Price','$Status','$Detail')"
);
$result = mysqli_affected_rows($conn);
mysqli_close($conn);
return $result;
}
//删除商品 状态为已上架商品不能删除
function deleteGoods($id){
$conn = DBHelper::getConnect();
$conn->query("delete from product where id=$id");
$result = mysqli_affected_rows($conn); //受影响行数
mysqli_close($conn);
return $result;
}
function updateGoods($id,$goods){
$Name = $goods->getName();
$Pic = $goods->getPic();
$Price = $goods->getPrice();
$Status = $goods->getStatus();
$Detail = $goods->getDetail();
$conn = DBHelper::getConnect();
$conn->query(
"update product set Name='$Name',Pic='$Pic',Price='$Price',Status='$Status',Detail='$Detail' WHERE id='$id'"
);
$result = mysqli_affected_rows($conn); //受影响行数
mysqli_close($conn);
return $result;
}
//获得所有商品
function queryAllGoods(){
$conn = DBHelper::getConnect();
$result = $conn->query("select * from product");
mysqli_close($conn);
return $result;
}
//获得单个商品
function querySingleGoods($id){
$conn = DBHelper::getConnect();
$result = $conn->query("select * from product where id=$id");
mysqli_close($conn);
return $result;
}
}
Service层
DAO与Controller之间的层
class GoodsService{
private $goodsDao;
/**
* GoodsService constructor.
* @param $goodsDao
*/
public function __construct()
{
$this->goodsDao = new GoodsDao();
}
//添加商品
function addGoods($goods){
return $this->goodsDao->addGoods($goods);
}
//删除商品
function deleteGoods($id){
return $this->goodsDao->deleteGoods($id);
}
//获得所有商品信息
function getAllGoods(){
$result = $this->goodsDao->queryAllGoods();
$arr = array();
if ($result->num_rows > 0) {
// 输出数据
while($row = $result->fetch_assoc()) {
//大坑!!!goods定义在外面,arr取的都是相同的(arr应该都是只插入对象地址)
$goods = new Goods();
$goods->setId($row["id"]);
$goods->setName($row["Name"]);
$goods->setPic($row["Pic"]);
$goods->setPrice($row["Price"]);
$goods->setDetail($row["Detail"]);
$goods->setStatus($row["Status"]);
$arr[] = $goods;
}
} else {
return json_encode("0结果");
}
return json_encode($arr,JSON_UNESCAPED_UNICODE);
}
//获得单个商品信息
function getGoods($id){
$result = $this->goodsDao->querySingleGoods($id);
if($result->num_rows > 0){
$goods = new Goods();
$row = $result->fetch_assoc();
$goods->setId($row["id"]);
$goods->setName($row["Name"]);
$goods->setPic($row["Pic"]);
$goods->setPrice($row["Price"]);
$goods->setDetail($row["Detail"]);
$goods->setStatus($row["Status"]);
return json_encode($goods,JSON_UNESCAPED_UNICODE);
} else {
return json_encode('null');
}
}
//商品信息修改 状态为已上架商品不能修改
function updateGoods($id,$goods){
return $this->goodsDao->updateGoods($id,$goods);
}
}
Controller层
这一层比较关键哦,是个前后端打交道的层,决定了如何与前端合作,好好看。
tips:有兴趣研究$_POST和$_FILES的小伙伴可以用print_r函数打印出来。
$Action = '';
if(isset($_POST['Action'])){
$Action = $_POST['Action'];
}
if($Action == 'addGoods'){//添加商品
$goods = new Goods();
$goods->setName($_POST['name']);
$goods->setPrice($_POST['price']);
$goods->setDetail($_POST['detail']);
$goods->setStatus($_POST['status']);
//判断是否存在文件
if (isset($_FILES["upfile"])){
//iconv将utf-8转为gbk,由于本地编码是GBK
$source = iconv("UTF-8","GBK//IGNORE",$_FILES['upfile']['tmp_name']);
$realPath = iconv("UTF-8","GBK//IGNORE",'../resource/img/'.$_FILES['upfile']['name']);
//print_r(mb_detect_encoding($realPath, array("ASCII",'UTF-8',"GB2312","GBK",'BIG5'))); //获得$realPath编码 GBK
//图片存入服务器
move_uploaded_file($source, $realPath);
//设置$realPath会乱码(此时$realPath编码为gbk)
$goods->setPic('../resource/img/'.$_FILES['upfile']['name']);
}else {
$goods->setPic('null');
echo json_encode("添加失败:图片未上传");
return;
}
//商品信息持久化
$goodsService = new GoodsService();
$result = $goodsService->addGoods($goods);
if($result > 0) echo json_encode("添加商品成功");
else echo json_encode("添加商品失败");
} else if($Action == 'queryAllGoods'){//获得所有商品信息
$goodsService = new GoodsService();
echo $goodsService->getAllGoods();
} else if($Action == 'deleteGoods'){ //删除商品
$goodsService = new GoodsService();
$result = $goodsService->deleteGoods($_POST['id']);
echo json_encode($result);
} else if($Action == 'queryGoods'){
$goodsService = new GoodsService();
echo $goodsService->getGoods($_POST['id']);
} else if($Action = 'updateGoods'){ //修改商品信息
$goods = new Goods();
$goods->setName($_POST['name']);
$goods->setPrice($_POST['price']);
$goods->setDetail($_POST['detail']);
$goods->setStatus($_POST['status']);
$goods->setPic($_POST['pic']);
//判断内存中是否存在文件,存在的话就不用再保存到服务器了
if (isset($_FILES["upfile"])){
//图片存入服务器
$source = iconv("UTF-8","GBK//IGNORE",$_FILES['upfile']['tmp_name']);
$realPath = iconv("UTF-8","GBK//IGNORE",'../resource/img/'.$_FILES['upfile']['name']);
move_uploaded_file($source, $realPath);
$goods->setPic('../resource/img/'.$_FILES['upfile']['name']);
}
//商品信息持久化
$goodsService = new GoodsService();
$result = $goodsService->updateGoods($_POST['id'],$goods);
if($result > 0){
echo json_encode("success");
} else {
echo json_encode('unchanged');
}
}
至此后端代码完结!!!
PHP项目运行遇到的坑
????????php表单提交时获取不到post数据的解决方法_hys__handsome的博客-CSDN博客
|