开始时间:2022-03-03
课程链接:米米商城
新增商品分析
我们下一步需要测试新增商品按钮
这里有一个类别的添加,这是需要读取我们的数据库,查看我们有多少
商品类别的开发
这里不是用controller,而是使用监听器
package listener;
import BUPT.pojo.ProductType;
import BUPT.service.ProductTypeService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.util.List;
@WebListener
public class ProductTypeListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
// 获取所有商品类型的列表,controller中是依赖注入的方式获取
//但这里是在监听器中,而spring框架的注册也是以监听器的形式注册的
//执行的接口都是同一个,没办法保证是这里的监听器先实现还是spring的注册先实现
//所以不能使用spring容器的依赖注入,只能手工取出
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext_*.xml");
ProductTypeService productTypeService = (ProductTypeService) context.getBean("ProductTypeServiceImpl");
List<ProductType> typeList = productTypeService.getAll();
//放入全局应用作用域中,供新增页面,修改页面,前台的查询功能提供全部商品类别集合
sce.getServletContext().setAttribute("typeList", typeList);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
}
}
然后还是在service里面搞实现类
接口
package BUPT.service;
import BUPT.pojo.ProductType;
import java.util.List;
public interface ProductTypeService {
List<ProductType> getAll();
}
实现类
package BUPT.service.impl;
import BUPT.mapper.ProductTypeMapper;
import BUPT.pojo.ProductType;
import BUPT.pojo.ProductTypeExample;
import BUPT.service.ProductTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service("ProductTypeServiceImpl")
public class ProductTypeServiceImpl implements ProductTypeService {
//在业务逻辑层中,一定会有数据访问层的对象,Spring来new出来
@Autowired
ProductTypeMapper productTypeMapper;
@Override
public List<ProductType> getAll() {
return productTypeMapper.selectByExample(new ProductTypeExample());
}
}
找到对应的addproject.jsp
写上对应的语句
<tr>
<td class="one">类别</td>
<td>
<select name="typeId">
<%--监听器里面setAttribute放的是什么就是什么,这里就是typeList--%>
<c:forEach items="${typeList}" var="type">
<option value="${type.typeId}">${type.typeName}</option>
</c:forEach>
</select>
</td>
</tr>
此时启动Tomcat,发现成功加载
异步Ajax图片上传分析
当我们选择了图片后,需要将其回显到图片介绍页里面
然后还要标注出我们选择图片的名称
在ProductInfoAction中,继续完善功能
因为上传到服务器,为了防止同名文件造成对前面文件的覆盖
我们需要给上传到服务器的文件名进行重命名
也是跟之前加密密文一样的类似操作
添加一个工具类FileNameUtil
package BUPT.utils;
import java.util.UUID;
public class FileNameUtil {
//根据UUID生成文件名
public static String getUUIDFileName() {
UUID uuid = UUID.randomUUID();
return uuid.toString().replace("-", "");
}
//从请求头中提取文件名和类型
public static String getRealFileName(String context) {
// Content-Disposition: form-data; name="myfile"; filename="a_left.jpg"
int index = context.lastIndexOf("=");
String filename = context.substring(index + 2, context.length() - 1);
return filename;
}
//根据给定的文件名和后缀截取文件名
public static String getFileType(String fileName){
//9527s.jpg
int index = fileName.lastIndexOf(".");
return fileName.substring(index);
}
}
ProductInfoAction中进行补充
//异步Ajax文件上传处理
@ResponseBody
@RequestMapping("/ajaxImg")
//文件上传url的定位url: '${pageContext.request.contextPath}/prod/ajaxImg.action
//这里就只需要写上ajaxImg
public Object ajaxImg(MultipartFile pimage, HttpServletRequest request) {
//实现上传功能
//提取生成文件名UUID+图片后缀名
String saveFileName = FileNameUtil.getUUIDFileName() + FileNameUtil.getFileType(pimage.getOriginalFilename());
//得到项目图片存储的路径
String path = request.getServletContext().getRealPath("/image_big");
//拿到的saveFileName是b641bd46ce6c476182f98224d758bc6d.jpg
//拿到的path是F:\编程学习\Java-Study\mimi_SSM\target\mimi_SSM-1.0-SNAPSHOT\image_big
//前两步拿到了文件名和所在原始路径,第三步转存,转存到我们上面写的这个路径里面去
//File.separator是为了动态获取文件分隔符,不同操作系统可能会不一样
//存放到F:\编程学习\Java-Study\mimi_SSM\image_big\XXX.jpg
try {
pimage.transferTo(new File(path + File.separator + saveFileName));
} catch (IOException e) {
e.printStackTrace();
}
//返回客户端JSON对象,封装图片的路径,为了在页面实现立即回显
JSONObject object = new JSONObject();
object.put("imgurl", saveFileName);
return object.toString();
}
这里要再和前端界面进行对接
addproject.jsp中补充,实现Ajax异步请求
<script type="text/javascript">
function fileChange() {//注意:此处不能使用jQuery中的change事件,因此仅触发一次,因此使用标签的:onchange属性
$.ajaxFileUpload({
url: '${pageContext.request.contextPath}/prod/ajaxImg.action',//用于文件上传的服务器端请求地址
secureuri: false,//一般设置为false
fileElementId: 'pimage',//文件上传控件的id属性 <input type="file" id="pimage" name="pimage" />
dataType: 'json',//返回值类型 一般设置为json
success: function (obj) //服务器成功响应处理函数
{
$("#imgDiv").empty(); //清空原有数据
//创建img 标签对象
var imgObj = $("<img>");
//给img标签对象追加属性
//回显也是从/image_big/往外取
//这里记得要补充上/mimi_SSM这个Tomcat发布的项目地址,不然回显找不到地址的
imgObj.attr("src", "/mimi_SSM/image_big/" + obj.imgurl);
imgObj.attr("width", "100px");
imgObj.attr("height", "100px");
//将图片img标签追加到imgDiv末尾
$("#imgDiv").append(imgObj);
//将图片的名称(从服务端返回的JSON中取得)赋值给文件本框
//$("#imgName").html(data.imgName);
},
error: function (e)//服务器响应失败处理函数
{
alert(e.message);
}
});
}
</script>
商品新增功能的开发
观察我们需要的数据
与数据库作为对比
可以发现除了p_date不能获取,其他都是可以直接从表单中得到的
我们在service包下的ProductInfoService接口中新增一个方法
int save(ProductInfo info);
并在实现类中进行实现
完成insert操作
@Override
public int save(ProductInfo info) {
return productInfoMapper.insert(info);
}
进一步在controller包下的ProductInfoAction进行save.action的书写
@RequestMapping("/save")
public String save(ProductInfo info, HttpServletRequest request) {
info.setpImage(saveFileName);
info.setpDate(new Date());
int num=-1;
try {
num=productInfoService.save(info);
} catch (Exception e) {
e.printStackTrace();
}
if(num>0){
request.setAttribute("msg","添加成功");
}else {
request.setAttribute("msg","添加失败");
}
//增加成功后需要重新访问数据库
return "forward:/prod/split.action";
}
再在addproduct.jsp中补充
<form action="${pageContext.request.contextPath}/prod/save.action" enctype="multipart/form-data"
method="post" id="myform">
看一看效果
商品更新功能
完成更新功能,首先要实现一个商品回显的功能
也就是说能在单击编辑时,得到更新商品页的所有数据的回显
需要在service中补充按主键获取对象的接口
ProductInfoService
//按主键ID查询的方法
ProductInfo getByID(int pid);
ProductInfoServiceImpl
@Override
public ProductInfo getByID(int pid) {
return productInfoMapper.selectByPrimaryKey(pid);
}
在controller中添加方法
//实现编辑功能时能加载该字段所有的数据,进行初始化,实现数据的呈现
@RequestMapping("/myupdate")
public String myshow(int pid, HttpServletRequest request) {
//清空之前的saveFileName
saveFileName = "";
//获取商品信息
ProductInfo info = productInfoService.getByID(pid);
//作用域名称用prod,是为了和前端对应
request.setAttribute("prod", info);
return "update";
}
将数据返回给update.jsp
我们发现这里涉及到了一个类型的复选框,怎么来实现选中某类商品,该商品的类型,复选框对应到其类型呢?
在update.jsp中,我们写上
<tr>
<td class="one">类别</td>
<td>
<select name="typeId">
<%--这里的typeList是和监听器的那里一致--%>
<c:forEach items="${typeList}" var="type">
<option value="${type.typeId}"
<%--读取所有的typeId和我们传过来的pro.typeId进行比较--%>
<%--当两者一致时,将复选框标为选中状态--%>
<c:if test="${type.typeId==prod.typeId}">
selected="selected"
</c:if>
>${type.typeName}</option>
</c:forEach>
</select>
</td>
</tr>
我们还要在product.jsp中,实现回显功能的提交
<td>
<button type="button" class="btn btn-info "
onclick="one(${p.pId},${info.pageNum})">编辑
</button>
<button type="button" class="btn btn-warning" id="mydel"
onclick="del(${p.pId})">删除
</button>
</td>
通过单击编辑按钮,跳转到编辑页面
function one(pid, ispage) {
//实现,点击”编辑“按钮时,向服务器提交请求,传递商品id,这里的pid是我们前面ProductInfoAction中写的参数名
location.href = "${pageContext.request.contextPath}/prod/myupdate.action?pid=" + pid + "&page=" + ispage;
}
此时我们就能正确得到预期的结果了
商品更新
service里面添加接口中的方法,并在ProductInfoServiceImpl新增实现方法
@Override
public int update(ProductInfo info) {
return productInfoMapper.updateByPrimaryKey(info);
}
controller里面新增一个update方法
当saveFileName不为空时,也就是说我们有过修改图片,那么就要更新info对象
@RequestMapping("/update")
public String update(ProductInfo info, HttpServletRequest request) {
//如果Ajax有过异步图片上传,则saveFileName里有上传来的图片的名称
//如果没有上传过,则saveFileName为空
//实体类info使用隐藏表单域提供pImage原始图片名称
// (我们已经在上面/save的末尾清空了saveFileName)
if (!saveFileName.equals("")) {
//说明有过异步上传的处理,有过上传肯定这里就读取了文件名
info.setpImage(saveFileName);
}
int num = -1;
try {
num = productInfoService.update(info);
} catch (Exception e) {
e.printStackTrace();
}
if (num > 0) {
//此时更新成功
request.setAttribute("msg", "更新成功");
} else {
request.setAttribute("msg", "更新失败");
}
//当返回的地址存在forward或redirect关键字时,自动屏蔽视图解析器,所以这里要写完整
return "forward:/prod/split.action";
}
对应前端update.jsp中的核心代码为
<div id="nav">
<p>商品管理>更新商品</p>
</div>
<script type="text/javascript">
function fileChange() {//注意:此处不能使用jQuery中的change事件,因此仅触发一次,因此使用标签的:onchange属性
$.ajaxFileUpload({
url: '${pageContext.request.contextPath}/prod/ajaxImg.action',//用于文件上传的服务器端请求地址
secureuri: false,//一般设置为false
fileElementId: 'pimage',//文件上传控件的id属性 <input type="file" id="pimage" name="pimage" />
dataType: 'json',//返回值类型 一般设置为json
success: function (obj) //服务器成功响应处理函数
{
$("#imgDiv").empty(); //清空原有数据
//创建img 标签对象
var imgObj = $("<img>");
//给img标签对象追加属性
imgObj.attr("src", "/mimi_SSM/image_big/" + obj.imgurl);
imgObj.attr("width", "100px");
imgObj.attr("height", "100px");
//将图片img标签追加到imgDiv末尾
$("#imgDiv").append(imgObj);
//将图片的名称(从服务端返回的JSON中取得)赋值给文件本框
//$("#imgName").html(data.imgName);
},
error: function (e)//服务器响应失败处理函数
{
alert(e.message);
}
});
}
</script>
这里和添加数据一样,实现图片回显
结束时间:2022-03-05