跳蚤市场-商品管理模块

跳蚤市场-商品管理模块

这里,我来聊聊写跳蚤小程序,我负责的是商品管理模块,聊天模块可以自行百度用webSocket技术可以实现!

1、数据库建表

USE tiaozao 
//这里并不是最终的数据库,懒得贴了,大体设置思路还是如下
CREATE TABLE t_ware (
	openid INT(19) NOT NULL PRIMARY KEY COMMENT '用户唯一id',
	wNo INT(20) NOT NULL COMMENT '商品编号',
	wName VARCHAR(20) NOT NULL COMMENT '商品名称',
	number INT COMMENT '商品数量',
	price DOUBLE COMMENT '商品价格',
	boss VARCHAR(20) COMMENT '商品提供者',
	b_comment VARCHAR(200) COMMENT 'boss要求+线下联系方式',
	up_shelf INT NOT NULL DEFAULT 0 COMMENT '是否已下架(0是上架,1是下架)',
	is_deleted INT COMMENT '逻辑删除',
	VERSION INT COMMENT '乐观锁版本号',
	gmt_create DATETIME COMMENT '创建时间',
	gmt_update DATETIME COMMENT '更改时间'

)ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='商品管理表';

CREATE TABLE t_footprint (

	openid INT(19) NOT NULL PRIMARY KEY COMMENT '用户唯一id',
	goods_id INT(20) NOT NULL COMMENT '商品编号',
	is_deleted INT COMMENT '逻辑删除'	

)ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='用户足迹表';

CREATE TABLE t_collections (
	openid INT NOT NULL PRIMARY KEY COMMENT '用户唯一id',
	classification VARCHAR(20) COMMENT '收藏标签分类',
	collections_id INT NOT NULL COMMENT '商品编号',
	is_deleted INT DEFAULT 0 COMMENT '逻辑删除'

)ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='用户收藏表';
---------------------------------------------------------------------------------
降序代码:select * from tab order by date DESC,table_id DESC

---------------------------------------------------------------------------------
关于字段的描述
看版本:5.0之前,括号里面是按字节算,5.0后以字符来算!!!
5.0版本的描述:mysql数据库中以 :数据类型(m)  来约束数据,其中 数字m在不同的数据类型中表示含义是不同的。 整型数系统已经限制了取值范围,tinyint占一个字节、int4个字节。所以整型数后面的m不是表示的数据长度,而是表示数据在显示时显示的最小长度(长度为字符数)。
tinyint(1) 这里的1表示的是 最短显示一个字符。tinyint(2) 这里的2表示的是 最短显示两个字符,但这里光设置m是没有意义的,你还需要指定当数据少于长度m时用什么来填充,比如zerofill(表示有0填充)。设置tinyint(2) zerofill 你插入1时他会显示01。设置tinyint(4) zerofill 你插入1时他会显示0001--------------------------------------------------------------------------------
1. 一个汉字占多少长度与编码有关:

UTF8:一个汉字=3个字节

GBK:一个汉字=2个字节

2.varchar(n)能存储几个汉字?

varchar(n)表示n个字符,无论汉字和英文,Mysql都能存入n个字符,仅是实际字节长度有所区别

2、参考代码

	查看所有的代码:
	Impl层:
	@Override
	public IPage<Order> searchOrderOfBase(String baseId, Integer page, Integer size) {
		if (page <= 0) {
			page = 1;
		}
		if (size <= 0) {
			size = 5;
		}
		Page<Order> orderPage = new Page<>(page, size);
		QueryWrapper<Order> wrapper = new QueryWrapper<>();
		wrapper.eq("base_id", baseId)
				.or()
				.eq("target_id", baseId);
		return orderMapper.selectPage(orderPage, wrapper);
	}
	
	-----------------------------------------------------------------------------------------
	Controller层:
	@GetMapping("/baseOrder/{id}")
	@ApiOperation("获取基地的所有订单")
	public Result searchOrderOfBase(@PathVariable(value = "id") String baseId) {
		if (StringUtils.isEmpty(baseId)) {
			return Result.error("查询失败");
		}
		return Result.success()
				.data((orderService.searchOrderOfBase(baseId)));
	}

3、上传图片和文字

一般图片上传和商品信息都是分开的接口,小程序一次只能上传一张图片,所以图片接口只能设置一次上传一张图片,然后返回前端文件名,多张图片就连续调用接口
,把这几次的文件名在前端那里拼接,最后跟商品信息上传就行!

关于网页:图片接口可以设置为一次上传多张,就设置一个MultipartFile[] file
即可,同时还可以在yaml文件配置上传文件大小,注意springboot2.x版本后要加上enabled: true才生效!
	@RequestMapping(value = "user/profilePhoto", produces = "application/json; charset=utf-8")
	@ResponseBody
	public boolean imageUphold(@RequestParam("photo") MultipartFile file, Long phone) throws IOException {
		String filePath = ducumentBase;// 保存图片的路径
		// String filePath = "/image";//保存图片的路径
		// 获取原始图片的拓展名
		String originalFilename = file.getOriginalFilename();
		System.out.println("originalFilename: " + originalFilename);
		// 新的文件名字
		String newFileName = UUID.randomUUID() + originalFilename;
		// 封装上传文件位置的全路径
		filePath += "/" + phone;
		System.out.println("filePath: " + filePath);
		File targetFile = new File(filePath, newFileName);
		if (!targetFile.exists()) {
			targetFile.mkdirs();
		}
		// 把本地文件上传到封装上传文件位置的全路径
		System.out.println("newFileName: " + newFileName);

		System.out.println("targetFile: " + targetFile.getName());
		System.out.println("phone: " + phone);
		//System.out.println("afterPhone");
		try {
			file.transferTo(targetFile);
		} catch (IllegalStateException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		String allPath=mappingPath + "/" + phone+ "/" + newFileName;
		System.out.println("存储路径为"+allPath);
		boolean result=onedayServiceImpl.updProfilePhoto(allPath, phone);//存在数据库中,其中allPath的数据库类型为varchar(1000)
		return result;
	}

4、关于查看分页的代码

   Impl层
   这里查询所有商品最开始代码:
   @Override
    public List<WareVo> getWaresByPage(int no, int size) {
        Page<Ware> page = new Page<>(no,size);
        QueryWrapper<Ware> wrapper = new QueryWrapper<>();
        wareMapper.selectPage(page, wrapper.orderByDesc("create_time"));
        List<Ware> records = page.getRecords();
        ArrayList<WareVo> list = new ArrayList<>();
        for (Ware item : records){
            WareVo wareVo = new WareVo();
            BeanUtils.copyProperties(item,wareVo);
            list.add(wareVo);
        }
        return list;
    }
    ----------------------------------------------------
    使用线程池之后
    @Override
    public Page<WareVo> getWaresByPage(String classificationId, int no, int size) {
        Future<List<WareVo>> records =executorService.submit(()-> wareMapper.getAllWareInfo(classificationId,(no - 1)*10,size));
        Page<WareVo> wareVoIPage = DataUtil.getPage(no, size,records);
        return wareVoIPage;
    }

5、发布

nohup java -Xms500m -Xmx500m -jar xiaoliang_ware-0.0.1-SNAPSHOT.jar >output01.log 2>& 1&
nohup java -Xms500m -Xmx500m -jar xiaoliang_picture-0.0.1-SNAPSHOT.jar >output01.log 2>& 1&

查看Linux内存:free -m	
查看负载:uptime

6、在Linux系统上查找jar包位置

locate jar包名字 
//例如,我的jar包名字是bookman,就可以用locate bookman命令查找位置

7、访问swagger地址

http://自己服务器IP地址:9003/swagger-ui.html#/
http://自己服务器IP地址:9106/swagger-ui.html#/

8、补充

    private String imgPath ;

    @ApiOperation(value = "获取不同类别商品信息分页",notes = "分页")
    @GetMapping("/ware/page/{no}/{size}")
    public R getAllWaresByPage(@ApiParam("第几页")@PathVariable("no") int no,
                               @ApiParam("每页记录数")@PathVariable("size") int size){
        List<WareVo> waresByPage = wareService.getWaresByPage(no, size);
        return R.ok().data("list",waresByPage);
    }

    //图片上传接口
    @ApiOperation(value = "添加商品信息")
    @PostMapping(value = "/authority/ware/uploadImage",produces = "application/json;charset=utf-8")
    @ResponseBody
    public R uploadImage(@RequestParam("file") MultipartFile file) {
        String uploadDir = uploadPath;
        try {
            String filename = UploadUtils.upload(file, uploadDir, file.getOriginalFilename());//这里可能有错,有try-catch
            imgPath = filename;
            if (file == null) {
                return R.error();
            }else {
                String imgUrl = System.getProperty("user.dir")+"/images/"+filename;
                return
            }
        } catch (Exception e) {
            e.printStackTrace();
            return R.error();
        }
    }

    @ApiOperation(value = "添加商品信息")
    @PostMapping("/authority/ware/info")
    public R addWareIf(@RequestParam("number") Integer number,
                       @RequestParam("price") Double price,
                       @RequestParam("Wname") String Wname,
                       @RequestParam("bComment") String bComment,
                       @RequestParam("userTags") String userTags) {

        return wareService.addWares(number,price,Wname,bComment,imgPath,userTags) ? R.ok() : R.error();

    }


    /**
     *  在线打开图片
     * @param fileName
     * @param request
     * @param response
     * @throws IOException
     */
    @ApiOperation(value = "在线打开商品图片")
    @GetMapping( "/ware/downloadImage/" )
    public void download(@ApiParam(value = "图片名字") @RequestParam("fileName") String fileName, HttpServletRequest request, HttpServletResponse response ) throws IOException
    {
        if( fileName != null )
        {
            UploadHelper.sendFile(
                    response,
                    uploadPath+"/images/"+fileName,/*uploadPath+fileName*/
                    fileName,
                    "inline",
                    "image/jpeg" );
            return ;
        }
    }

9、bug总结

1、不能使用mybatis-plus的sql优化拦截器
		//性能优化拦截器 不符合的sql会被拦下来不执行
        //interceptor.addInnerInterceptor(new IllegalSQLInnerInterceptor());
        
2、自动填充,格式要一样,比如名字和类型(DateLocalDateTime)、不然无法自动填充

3、主键要用Long(对应bigint)、varchar(对应String)

4、数据库中非空的,插入时一定要赋值

5、要善用in关键字,以后写sql关键字要用大写,然后DISTINCT要写在字段的前面,LIMIT要放在最后,和首页从0开始,前端第一页就是返回1

6、拦截路径要从端口号之后写起。

7、要进入对应目录,在发布jar包,不然容易起冲突,不起作用!

8、像filename名字这么长的,要用@RequestParam,不能用url传过来,@Paramvariable9[root@iZ8vbesz24k2nz1c85g3s5Z images]# mv xiaoliang_picture-0.0.1-SNAPSHOT.jar /root/zktiaozao/ #移动文件命令

10Long类型的要转为字符型的(用Maven引入jackson依赖即可)
依赖如下:
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.3</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.3</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.9.3</version>
        </dependency>
同时在所需字段加上:@JsonSerialize(using = ToStringSerializer.class)即可转为字符串!

10、关于动态网关

详细地址:https://www.jb51.net/article/203766.htm
		★https://zhuanlan.zhihu.com/p/128087364
		 https://gitee.com/zlt2000/microservices-platform/tree/master/zlt-gateway/sc-gateway/src/main/java/com/central/gateway
★这个不错: https://www.jianshu.com/p/8f007bcf36ea
★这个很不错:https://www.zhuxianfei.com/java/33493.html

11、关于openFeign

介绍:https://segmentfault.com/a/1190000012496398

12、注册的appID和APPsecret

自己查找微信开发文档按照介绍注册账号就有如下内容:
appId: ******
appSecret密匙:**********

13、关于设置jwt

链接1:https://vimsky.com/examples/detail/java-method-org.jose4j.jwt.JwtClaims.getSubject.html

链接2:http://www.leftso.com/blog/221.html

14、优化

关于sql优化:
关于Impl:创建一个线程池,实现ThreadPoolExecutor,创建线程池!!
关于统一放回值Result()可以修改,避免反复调用Result()方法,重复劳动!

线程池配置如下:


import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.*;

/**
 1. @author 小亮
 2. @date 2021/8/8  -  10:18
 */
@Configuration
@ConfigurationProperties(prefix = "tiaozao.thread.pool") //在yaml文件里面配置
public class AsyncConfig {

    private int corePoolSize; // 核心线程池大小
    private int maxinumPoolSize; // 最大核心线程池大小
    private int keepAliveTime; // 超时了没有人调用就会释放


    @Bean
    public ExecutorService executorService() {  //真正的线程池接口
        ExecutorService threadPool = new ThreadPoolExecutor( //ThreadPoolExecutor实现子类,其实可以用单线程池也不错
                corePoolSize,
                maxinumPoolSize,
                keepAliveTime,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(maxinumPoolSize - corePoolSize),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy()
        );
        return threadPool;
    }

    public int getCorePoolSize() {
        return corePoolSize;
    }

    public void setCorePoolSize(int corePoolSize) {
        this.corePoolSize = corePoolSize;
    }

    public int getMaxinumPoolSize() {
        return maxinumPoolSize;
    }

    public void setMaxinumPoolSize(int maxinumPoolSize) {
        this.maxinumPoolSize = maxinumPoolSize;
    }

    public int getKeepAliveTime() {
        return keepAliveTime;
    }

    public void setKeepAliveTime(int keepAliveTime) {
        this.keepAliveTime = keepAliveTime;
    }
}

好了,分享到这里结束了,有兴趣或者志同道和的朋友可以留言或者加我微信:w134133wei

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值