毕业季--各应用场景案例使用技术
当当网中的邮件发送功能。
本身邮件发送功能不难,就是借助了工具类JavaMail的工具类,我们调用工具类的发送邮件的方法即可完成,方法的参数有收件人,邮件标题和邮件内容。我们在包装这个功能的时候可以把他应用到一个场景里面。比如:我们定期给用户发送网站营销的一些电子邮件。在营销推广模块,我们可以写出这个功能。
当当网中的支付宝支付功能。
- 在当当网里面引入jar包。
com.alipay.sdk alipay-sdk-java 4.13.50.ALL
- 引入工具类。根据自己的支付宝沙箱环境修改工具类中的属性常量。
- 把工具类加入到spring中让,spring管理起来这个类。在spring配置文件中加入一个配置项
- 写控制器类
@Autowired
private AlipayTemplate at;
@RequestMapping("pay")
public void payMoney(HttpServletResponse response) throws Exception {PayVo pv=new PayVo();pv.setOut_trade_no("200");pv.setSubject("aaaa");pv.setTotal_amount("100");//告知浏览器响应的是一个html字符串response.setContentType("text/html");String pay = at.pay(pv);//支付的html源码response.getWriter().print(pay);
}
- 测试,输入控制器地址会到支付页面。
使用SpringAop和RabbitMQ实现日志的记录功能。
思路:

操作步骤:
- 建表,把日志表创建出来。
- 用mybatisplus生成log模块的增删改查基础代码。
- 把日志模块的springboot环境搭建起来。创建配置文件,创建入口类。
- 到商品模块中给业务类增加额外功能。LogAspect(springaop的额外增强类。)。
- LogAspect中准备log对象的各个属性值。封装到log对象里面。把log对象转换为一个json串,通过rabbitmq的生产者代码把json串作为一个消息发给rabbitmq的消息队列。
- 在日志模块中增加一个监听消息队列收到消息的监听器。这个监听器就是rabbitmq的消费者。消费者收到消息后,将json串转换为log对象,然后调用业务类的插入方法把日志对象存储到数据库里面。
Redis中秒杀的功能。
商城项目中有个秒杀功能,一元抢iphone手机。商城有十台iphone要促销,吸引顾客。现在要抢的人比较多。并发量大。
- 第一版代码
@GetMapping("/secKill")
public String secKill(int pid){String key="product:"+pid;//获取到操作string的工具类ValueOperations stringObjectValueOperations = redisTemplate.opsForValue();//获取到redis里面商品的数量Integer count = (Integer)stringObjectValueOperations.get(key);//判断商品数量是否大于0if(count>0){//大于0了就对商品数量减一stringObjectValueOperations.decrement(key);System.out.println("购买成功,还剩"+(count-1)+"个");return "购买成功,还剩"+count+"个";}System.out.println("购买失败");return "购买失败";
}
第一版代码在多线程的环境中运行是有问题的。
- 第二版使用redis的乐观锁
@GetMapping("/secKill2")
public String secKill2(int pid){//1.先获取redis里面的库存数量String key="product:"+pid;//开启一下事务redisTemplate.setEnableTransactionSupport(true);redisTemplate.watch(key);ValueOperations stringObjectValueOperations = redisTemplate.opsForValue();Integer count = (Integer) stringObjectValueOperations.get(key);redisTemplate.multi();//2.判断是否大于0if (count > 0) {//让库存减一,把库存减一放入到一个事务里面,然后监听product:1这个键是否被其他事务修改stringObjectValueOperations.decrement(key);}List
第二版的代码会出现很多人抢商品但是到最后商品还有留存的问题。
-
第三版使lua脚本实现原子操作
lua脚本:
local prodid=KEYS[1];
local qtkey="product:"..prodid;
local num= redis.call("get" ,qtkey);
if tonumber(num)<=0 then return 0;
else redis.call("decr",qtkey);
end
return tonumber(num);
@GetMapping("/secKill3")
public String secKill3(int pid){long result = 0;try {//调用lua脚本并执行DefaultRedisScript redisScript = new DefaultRedisScript<>();redisScript.setResultType(Long.class);//返回类型是Long//lua文件存放在resources目录下redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("test.lua")));result = redisTemplate.execute(redisScript, Arrays.asList(pid+""));} catch (Exception e) {e.printStackTrace();}if(result>0){System.out.println("购买成功,还剩"+(result-1)+"个");return "购买成功,还剩"+(result-1)+"个";}System.out.println("购买失败");return "购买失败";
}
Redis中验证码结合手机信息的验证功能。
要求:
- 收入手机号,点击发送后生成六位验证码,2分钟内有效
- 收入验证码点击验证,返回成功或者失败。
- 每个手机号每天只能输入三次。
//手机号
private static final String PHONE="15009876543";
//redis里面存储的两个key的名字,一个键叫15009876543:code,另一个叫15009876543:count
private static final String CODEKEY=PHONE+":code";
private static final String COUNTKEY=PHONE+":count";
//验证手机跟用户输入的验证码是否一致
@Test
public void verifyCode(){String userCode="555305";Jedis jedis = JedisUtil.getJedis();String realCode = jedis.get(CODEKEY);jedis.close();if(userCode.equalsIgnoreCase(realCode)){System.out.println("验证码一致!");}else{System.out.println("验证码有误!");}
}@Test
//给手机发信息,保证两分钟有效,保证一天发送三次
public void testSendMsg(){//验证该手机号是否超过次数Jedis jedis= JedisUtil.getJedis();String countValue = jedis.get(COUNTKEY);//从redis里面获取到该手机号当天发了几次。if(countValue==null){//设置key和值的同时,给键一个超时时间expirejedis.setex(COUNTKEY,24*60*60,"1");}else{int count = Integer.parseInt(countValue);//一天还没有超过3次if(count<3){jedis.incr(COUNTKEY);//让redis的countkey自增一下}else{//超过三次System.out.println("一天不能超过三次");return;}}String code = generateCode();//生成验证码//调用工具类给手机发信息System.out.println("给手机发送了一个验证码:"+code);jedis.setex(CODEKEY,120,code);//把验证码放入到了redis里面。jedis.close();}
public String generateCode(){Random random=new Random();StringBuilder result=new StringBuilder();for(int i=0;i<6;i++){int num = random.nextInt(10);result.append(num);}return result.toString();
}
用户模块认证和授权功能。
主要的表有三个:用户表(bz_admin),角色表(bz_role),菜单表(bz_menu).
用户表和角色表之间有多对多关系。关系表:bz_admin_role
角色表和菜单表有多对多关系。关系表:bz_role_resource

商品模块的商品属性表的设计
商品模块复杂的是表设计,最初设计是只有一个张商品表。但是有一个问题就是不同类型的商品属性是不一样的。比如手机有cpu和屏幕这些属性,但是衣服没有,衣服有颜色,尺寸,布料这些属性。一个大型商城系统需要很多类型的商品。所以不适合建到一张表里面。
我们为了能够灵活存储商品属性我们又设计了一个属性表,来存储各个类型的商品都有哪些不同的属性,一个属性就对应属性表里面的一行数据。
然后我们需要存储每个商品的商品属性值,这时候我们又创建了一个属性值表。来存储每个属性对应的属性值。
这样就巧妙地把商品表中的列转换成了另外两张表的行数据。

修改后一张表被改为下面四张表
ES的站内分词高亮查询功能。


seata实现分布式事务,下订单时库存和订单的事务问题。

- 一阶段:执行本地事务,并返回执行结果
- 二阶段:根据一阶段的结果,判断二阶段做法:提交或回滚
Seata在第一极端先做用户的sql,在做用户的sql前会记录数据日志信息。当需要回滚的的时候seata会将数据进行自动恢复,不需要程序写补偿代码。
使用分布式锁解决缓存击穿的功能。

redis分布式锁代码
/*** 分布式锁*/
public List getDataByRedisLock(){List nodeList = null;//生成UUIDString uuid = UUID.randomUUID().toString();//1.获取锁 执行业务代码 set nx (setIfAbsent)//setIfAbsent 该方法如果设置了过期时间 底层就是 set Ex nx 加锁和过期时间设置是原子性的Boolean lock = redisTemplate.opsForValue().setIfAbsent("redis-lock", uuid,100,TimeUnit.SECONDS);if (lock){System.out.println("获取锁");//加锁成功查询数据库try {nodeList = getNodesByMysql();}finally {//查询完成解锁String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then return redis.call(\"del\",KEYS[1]) else return 0 end";/*** 参数1 脚本* 参数2 要删除的key* 参数3 uuid*/redisTemplate.execute(new DefaultRedisScript(script,Long.class),Arrays.asList("redis-lock"),uuid);}}else {try {System.out.println("没有获取锁重试");Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}//重试getDataByRedisLock();}return nodeList;
}
EasyPoi的excel导入导出功能。
在项目中使用excel导入导出是一个很常用的功能,比如到导出商品类别信息或者导出用户信息到excel里面,都可以作为项目开发经验写到简历里面。
使用步骤:
- 实体类加注解
@Data
public class BzBrand implements Serializable {@Excel(name = "品牌id")private Long brandId;@Excel(name = "品牌名字")private String name;@Excel(name = "首字母")private String firstLetter;@Excel(name = "显示状态")private Integer showStatus;
}
-
直接完成导入导出
导出:
/*** 导出*/
@Test
public void test1() throws Exception {/*** 准备数据*/List BzBrands = brandMapper.selectAll();/*** 导出参数对象* 参数1 标题* 参数2 表名*/ExportParams params = new ExportParams("所有的品牌数据","brands");Workbook workbook = ExcelExportUtil.exportExcel(params, BzBrand.class, BzBrands);workbook.write(new FileOutputStream("E://easyBrands.xls"));
}
导入:
/*** 导入*/@Testpublic void test2() throws Exception {FileInputStream inputStream = new FileInputStream("E://easyBrands.xls");/*** 导入参数对象* setTitleRows 声明标题占有的行数* setHeadRows 声明表头占有的行数*/ImportParams importParams = new ImportParams();importParams.setTitleRows(1);importParams.setHeadRows(1);/*** 导入方法* 参数1 流* 参数2 类对象* 参数3 导入参数对象*/List BzBrands = ExcelImportUtil.importExcel(inputStream, BzBrand.class, importParams);for (BzBrand brand : BzBrands) {System.out.println(brand);}}
-
值的替换
当导出数据时,需要对数据进行转换,比如显示状态 (0->不显示,1->显示)。就需要在导出时,对值进行替换。
@Data
public class BzBrand implements Serializable {@Excel(name = "品牌id")private Long brandId;@Excel(name = "品牌名字")private String name;@Excel(name = "首字母")private String firstLetter;@Excel(name = "显示状态",replace={"不显示_0","显示_1"})private Integer showStatus;
}
拍卖系统的拍卖功能
拍卖系统的主要表的设计:
create table t_auction(auctionId int primary key auto_increment, -- 主键 编号auctionName varchar(500), -- 拍卖品名称auctionStartPrice double, -- 拍卖品起拍价auctionUpset double, -- 拍卖品底价auctionStartTime date, -- 开始时间auctionEndTime date , -- 结束时间auctionPic varchar(500), -- 拍卖品老图片auctionDesc varchar(200) -- 拍卖品描述
);
create table auction_user(userId int primary key auto_increment, -- 主键userName varchar(50),-- 用户名userPassword varchar(50),-- 用户密码userIsadmin int -- 是否为管理员 0普通用户 1管理员
);
create table auction_record(record_id int primary key auto_increment, -- 主键record_time timestamp,-- 竞拍时间record_price double, -- 竞拍出价user_id int , -- 用户编号 外键 (用户表)auction_id int, -- 拍卖品编号 外键(拍卖品表)
);
学校的评论功能

评论系统的主要表设计:
create table t_school(id int primary key auto_increment,name varchar(30) not null,description varchar(200) not null
);
-- 学校和评论外键 用户和评论外键
create table t_user(id int primary key auto_increment,username varchar(30) not null,password varchar(30) not null
);
-- 点赞方法redis,评论下的评论用一级类别二级类别
create table t_comment(id int primary key auto_increment,pid int,content varchar(255) not null,sid int not null,uid int not null,create_time date not null
);
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
