ZZJ_淘淘商城项目:day03(淘淘商城02 - 后台系统功能实现)
1. 今日大纲
1、 学习Nginx的使用
2、 实现商品的管理
a) 新增商品
b) 查询商品列表
c) 编辑商品
d) 删除商品
e) 上架和下架商品
SwitchHosts!_win_x64_3.5.0(5486)
https://oldj.github.io/SwitchHosts/
使用SwitchHosts!修改本地hosts文件,实现ip地址和域名的解析。
Win10系统的hosts目录为:
C:\Windows\System32\drivers\etc
Linux下的hosts文件所在路径: /etc/hosts
# taotao2016 开发环境 127.0.0.1 www.taotao.com 127.0.0.1 manage.taotao.com 127.0.0.1 image.taotao.com
修改配置conf/nginx.conf
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; gzip on; server { listen 80; server_name manage.taotao.com; #charset koi8-r; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; location / { proxy_pass http://127.0.0.1:8081; proxy_connect_timeout 600; proxy_read_timeout 600; } } server { listen 80; server_name image.taotao.com; #charset koi8-r; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; location / { root F:\\javaweb\\taotao-upload; } } }
使用nginx实现反向代理监听端口
Shift+鼠标右键启动Powershell ls F:\javaweb\nginx-1.16.1 #powershell启动和关闭nginx.exe服务 .\nginx -c conf\taotao2016.conf .\nginx -s stop
.\nginx -s reload
Spring4.3.25版本集成使用通用Mapper,可以使用泛型注入的新特性。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.taotao.manage.service; import java.util.Date; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.taotao.manage.pojo.BasePojo; import tk.mybatis.mapper.common.Mapper; import tk.mybatis.mapper.entity.Example; public abstract class BaseService<T extends BasePojo> { /** * 方法: 1、 queryById 2、 queryAll 3、 queryOne 4、 queryListByWhere 5、 queryPageListByWhere 6、 save 7、 update 8、 deleteById 9、 deleteByIds 10、 deleteByWhere */ // public abstract Mapper<T> getMapper(); // spring4.3.25支持泛型注入新特性 @Autowired private Mapper<T> mapper; /** * 根据id查询数据 * @param id * @return */ public T queryById(Long id) { return this.mapper.selectByPrimaryKey(id); } /** * 查询所有数据 * @return */ public List<T> queryAll(){ return this.mapper.selectAll(); } /** * 根据条件查询一条数据 * 如果该条件所查询的数据为多条会抛出异常 * @param record * @return */ public T queryOne(T record) { return this.mapper.selectOne(record); } /** * 根据条件查询多条数据 * @param record * @return */ public List<T> queryListByWhere(T record){ return this.mapper.select(record); } /** * 根据条件分页查询数据 * @param record * @param pageNum * @param pageSize * @return */ public PageInfo<T> queryPageListByWhere(T record,Integer pageNum,Integer pageSize){ //设置分页参数 PageHelper.startPage(pageNum, pageSize); List<T> list = this.mapper.select(record); return new PageInfo<T>(list); } /** * 新增数据,未设置的值为null * @param t * @return */ public Integer save(T t) { t.setCreated(new Date()); t.setUpdated(t.getCreated()); return this.mapper.insert(t); } /** * 选择不为null的字段作为插入更新数据 * @param t * @return */ public Integer saveSelective(T t) { t.setCreated(new Date()); t.setUpdated(t.getCreated()); return this.mapper.insertSelective(t); } /** * 更新数据,未设置的字段值为null * @param t * @return */ public Integer update(T id) { id.setUpdated(new Date()); return this.mapper.updateByPrimaryKey(id); } /** * 更新不为null的字段作为更新的字段 * @param t * @return */ public Integer updateSelective(T id) { id.setUpdated(new Date()); id.setCreated(null); //强制设置创建时间为null,永远不会被更新 return this.mapper.updateByPrimaryKeySelective(id); } /** * 根据主键id删除数据(物理删除) * @param id * @return */ public Integer deleteById(Long id) { return this.mapper.deleteByPrimaryKey(id); } /** * 根据主键ids批量删除数据(物理删除) * @param ids * @param clazz * @param property * @return */ public Integer deleteByIds(List<Object> ids ,Class<T> clazz,String property) { Example example = new Example(clazz); //设置条件,andIn(数据库字段,12345) example.createCriteria().andIn(property, ids); return this.mapper.deleteByExample(example); } /** * 根据条件删除数据 * @param record * @return */ public Integer deleteByWhere(T record) { return this.mapper.delete(record); } }
mysql数据库的bigint类型对应JAVA中的Long
item-add.jps的第115行修改restful风格的ajax请求:
//提交到后台的RESTful $.ajax({ type: "POST", url: "/rest/item", data: $("#itemAddForm").serialize(), statusCode: { 201: function() { $.messager.alert('提示','新增商品成功!'); }, 400: function() { $.messager.alert('提示','提交的参数不合法!'); }, 500: function() { $.messager.alert('提示','新增商品失败!'); } } });
通过日志查看操作Item表和ItemDesc表,由于在Service层的:同一个类、同一个方法,并且已经配置好了spring的AOP管理事务。
信息: Starting ProtocolHandler ["http-bio-8081"] 2019-11-03 09:27:59,142 [http-bio-8081-exec-1] [com.alibaba.druid.pool.DruidDataSource]-[INFO] {dataSource-1} inited 2019-11-03 09:27:59,175 [http-bio-8081-exec-1] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Creating a new SqlSession 2019-11-03 09:27:59,184 [http-bio-8081-exec-1] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4be7a5c4] 2019-11-03 09:27:59,265 [http-bio-8081-exec-1] [org.mybatis.spring.transaction.SpringManagedTransaction]-[DEBUG] JDBC Connection [com.mysql.jdbc.JDBC4Connection@1e0b3b6e] will be managed by Spring 2019-11-03 09:27:59,269 [http-bio-8081-exec-1] [com.taotao.manage.mapper.ItemMapper.insert]-[DEBUG] ==> Preparing: INSERT INTO tb_item ( created,updated,id,title,sell_point,price,num,barcode,image,cid,status ) VALUES( ?,?,?,?,?,?,?,?,?,?,? ) 2019-11-03 09:27:59,295 [http-bio-8081-exec-1] [com.taotao.manage.mapper.ItemMapper.insert]-[DEBUG] ==> Parameters: 2019-11-03 09:27:59.17(Timestamp), 2019-11-03 09:27:59.17(Timestamp), null, Z7(String), 970M(String), 500000(Long), 1(Integer), 2(String), (String), 163(Long), 1(Integer) 2019-11-03 09:27:59,303 [http-bio-8081-exec-1] [com.taotao.manage.mapper.ItemMapper.insert]-[DEBUG] <== Updates: 1 2019-11-03 09:27:59,307 [http-bio-8081-exec-1] [com.taotao.manage.mapper.ItemMapper.insert!selectKey]-[DEBUG] ==> Executing: SELECT LAST_INSERT_ID() 2019-11-03 09:27:59,320 [http-bio-8081-exec-1] [com.taotao.manage.mapper.ItemMapper.insert!selectKey]-[DEBUG] <== Total: 1 2019-11-03 09:27:59,320 [http-bio-8081-exec-1] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4be7a5c4] 2019-11-03 09:27:59,332 [http-bio-8081-exec-1] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4be7a5c4] from current transaction 2019-11-03 09:27:59,334 [http-bio-8081-exec-1] [com.taotao.manage.mapper.ItemDescMapper.insert]-[DEBUG] ==> Preparing: INSERT INTO tb_item_desc ( created,updated,item_id,item_desc ) VALUES( ?,?,?,? ) 2019-11-03 09:27:59,335 [http-bio-8081-exec-1] [com.taotao.manage.mapper.ItemDescMapper.insert]-[DEBUG] ==> Parameters: 2019-11-03 09:27:59.332(Timestamp), 2019-11-03 09:27:59.332(Timestamp), 3(Long), qq(String) 2019-11-03 09:27:59,336 [http-bio-8081-exec-1] [com.taotao.manage.mapper.ItemDescMapper.insert]-[DEBUG] <== Updates: 1 2019-11-03 09:27:59,336 [http-bio-8081-exec-1] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4be7a5c4] 2019-11-03 09:27:59,337 [http-bio-8081-exec-1] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4be7a5c4] 2019-11-03 09:27:59,337 [http-bio-8081-exec-1] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4be7a5c4] 2019-11-03 09:27:59,337 [http-bio-8081-exec-1] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4be7a5c4]
5.2. 上传组件的JS实现的上传参数
5.3.实现springMVC图片上传
1.导入 commons-fileupload 的依赖坐标
<!-- 文件上传组件 --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> </dependency>
2.配置文件上传解析器在springmvc.xml
<!-- 定义文件上传解析器 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 设定默认编码 --> <property name="defaultEncoding" value="UTF-8"></property> <!-- 设定文件上传的最大值5MB,5*1024*1024 --> <property name="maxUploadSize" value="5242880"></property> </bean>
3.PicUploadController使用了配置文件中的路径,读取配置文件用Service层spring父容器的一个“读取配置文件的类” 的 public关键字修饰的成员属性
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.taotao.manage.controller; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.Date; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.RandomUtils; import org.apache.commons.lang3.StringUtils; import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import com.fasterxml.jackson.databind.ObjectMapper; import com.taotao.common.bean.PicUploadResult; import com.taotao.manage.service.PropertieService; /** * 图片上传 */ @Controller @RequestMapping("/pic") public class PicUploadController { //创建日志对象 private static final Logger LOGGER = LoggerFactory.getLogger(PicUploadController.class); @Autowired private PropertieService propertieService; private static final ObjectMapper mapper = new ObjectMapper(); // 允许上传的格式 private static final String[] IMAGE_TYPE = new String[] { ".bmp", ".jpg", ".jpeg", ".gif", ".png" }; @PostMapping(value = "/upload", produces = MediaType.TEXT_PLAIN_VALUE) @ResponseBody public String upload(@RequestParam("uploadFile") MultipartFile uploadFile , HttpServletResponse response) throws Exception { // 校验图片格式 boolean isLegal = false; for (String type : IMAGE_TYPE) { //忽略大小写比较字符串的末尾 if (StringUtils.endsWithIgnoreCase(uploadFile.getOriginalFilename(), type)) { isLegal = true; break; } } // 封装Result对象,并且将文件的byte数组放置到result对象中 PicUploadResult fileUploadResult = new PicUploadResult(); // 状态 fileUploadResult.setError(isLegal ? 0 : 1); // 文件新路径 String filePath = getFilePath(uploadFile.getOriginalFilename()); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Pic file upload .[{}] to [{}] .", uploadFile.getOriginalFilename(), filePath); } // 生成图片的绝对引用地址 String picUrl = StringUtils.replace(StringUtils.substringAfter(filePath, propertieService.REPOSITORY_PATH), "\\", "/"); fileUploadResult.setUrl(propertieService.IMAGE_BASE_URL + picUrl); File newFile = new File(filePath); // 写文件到磁盘 uploadFile.transferTo(newFile); // 校验图片是否合法 isLegal = false; try { BufferedImage image = ImageIO.read(newFile); if (image != null) { fileUploadResult.setWidth(image.getWidth() + ""); fileUploadResult.setHeight(image.getHeight() + ""); isLegal = true; } } catch (IOException e) { } // 状态 fileUploadResult.setError(isLegal ? 0 : 1); if (!isLegal) { // 不合法,将磁盘上的文件删除 newFile.delete(); } response.setContentType(MediaType.TEXT_HTML_VALUE); //将java对象序列化成json数据 return mapper.writeValueAsString(fileUploadResult); } private String getFilePath(String sourceFileName) { String baseFolder = propertieService.REPOSITORY_PATH + File.separator + "images"; Date nowDate = new Date(); // yyyy/MM/dd String fileFolder = baseFolder + File.separator + new DateTime(nowDate).toString("yyyy") + File.separator + new DateTime(nowDate).toString("MM") + File.separator + new DateTime(nowDate).toString("dd"); File file = new File(fileFolder); if (!file.isDirectory()) { // 如果目录不存在,则创建目录 file.mkdirs(); } // 生成新的文件名 String fileName = new DateTime(nowDate).toString("yyyyMMddhhmmssSSSS") + RandomUtils.nextInt(100, 9999) + "." + StringUtils.substringAfterLast(sourceFileName, "."); return fileFolder + File.separator + fileName; } }
Spring容器 -- 父容器
SpringMVC容器 -- 子容器
父子容器的关系:
1、 子容器能够访问父容器的资源(bean)
a) 示例:Controller可以注入Service
2、 父容器不能访问子容器的资源(bean)
package com.taotao.manage.service; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @Service public class PropertieService { // 加载spring父容器中配置文件内容 @Value("${REPOSITORY_PATH}") public String REPOSITORY_PATH; @Value("${IMAGE_BASE_URL}") public String IMAGE_BASE_URL; }
对文件做校验:
1、 类型,通过文件的后缀名
2、 大小
3、 上传文件的内容做校验
a) 通过获取文件的宽和高来判断是否是图片
7. 日志的书写
总结:
1、 方法的入参处需要将参数打印出
2、 业务执行的状态发生变化时,需要打印
3、 异常处需要打印
6. 查询商品列表
EasyUI的datagrid的格式化输出。
默认情况下,会直接显示返回的数据,但是有些情况下不能直接显示,如:价格、日期、性别,需要指定formatter函数。
@Service public class ItemListService extends BaseService<Item> { @Autowired ItemMapper itemMapper; //根据商品更新时间降序排序 public EasyUIResult queryItemList(Integer page, Integer rows) { //第三个参数:是否count查询 PageHelper.startPage(page, rows, true); //设置查询条件 Example example = new Example(Item.class); example.setOrderByClause("updated DESC"); List<Item> list = itemMapper.selectByExample(example); PageInfo<Item> pageInfo = new PageInfo<>(list); // 返回给视图层一个包装好的EasyUIResult对象 return new EasyUIResult(pageInfo.getTotal(), pageInfo.getList()); } }
=====================================
end