专栏:高并发---分布式项目
亿级高并发电商项目-- 实战篇 --万达商城项目搭建 一 (商家端与用户端功能介绍、项目技术架构、数据库表结构等设计) | 亿级高并发电商项目-- 实战篇 --万达商城项目搭建 一 (商家端与用户端功能介绍、项目技术架构、数据库表结构等设计)_童小纯的博客-CSDN博客 |
亿级高并发电商项目-- 实战篇 --万达商城项目 二(Zookeeper、Docker、Dubbo-Admin等搭建工作 | 亿级高并发电商项目-- 实战篇 --万达商城项目 二(Zookeeper、Docker、Dubbo-Admin等搭建工作_童小纯的博客-CSDN博客 |
亿级高并发电商项目-- 实战篇 --万达商城项目 三(通用模块、商品服务模块、后台API模块、IDEA忽略文件显示等开发工作 | 亿级高并发电商项目-- 实战篇 --万达商城项目 三(通用模块、商品服务模块、后台API模块、IDEA忽略文件显示等开发工作_童小纯的博客-CSDN博客 |
亿级高并发电商项目-- 实战篇 --万达商城项目 四(Dashboard服务、设置统一返回格式与异常处理、Postman测试接口 ) | 亿级高并发电商项目-- 实战篇 --万达商城项目 四(Dashboard服务、设置统一返回格式与异常处理、Postman测试接口 )_童小纯的博客-CSDN博客 |
亿级高并发电商项目-- 实战篇 --万达商城项目 五 (用户服务模块、管理员模块功能 增、删、改、查 、分页,前端工程) | 亿级高并发电商项目-- 实战篇 --万达商城项目 五 (用户服务模块、管理员模块功能 增、删、改、查 、分页,前端工程)_童小纯的博客-CSDN博客 |
亿级高并发电商项目-- 实战篇 --万达商城项目 六(编写角色管理、用户权限(Spring Security认证授权)、管理员管理等模块) | 亿级高并发电商项目-- 实战篇 --万达商城项目 六(编写角色管理、用户权限(Spring Security认证授权)、管理员管理等模块)_童小纯的博客-CSDN博客 |
亿级高并发电商项目-- 实战篇 --万达商城项目 七(品牌模块、商品类型模块等开发) | 亿级高并发电商项目-- 实战篇 --万达商城项目 七(品牌模块、商品类型模块等开发)_童小纯的博客-CSDN博客 |
亿级高并发电商项目-- 实战篇 --万达商城项目 八(安装FastDFS、安装Nginx、文件服务模块、文件上传功能、商品功能与秒杀商品等功能) | 亿级高并发电商项目-- 实战篇 --万达商城项目 八(安装FastDFS、安装Nginx、文件服务模块、文件上传功能、商品功能与秒杀商品等功能)_童小纯的博客-CSDN博客 |
👏作者简介:大家好,我是小童,Java开发工程师,CSDN博客博主,Java领域新星创作者
📕系列专栏:前端、Java、Java中间件大全、微信小程序、微信支付、若依框架、Spring全家桶
📧如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀
🔥如果感觉博主的文章还不错的话,请👍三连支持👍一下博主哦
🍂博主正在努力完成2023计划中:以梦为马,扬帆起航,2023追梦人
编写广告服务接口
接下来我们编写广告相关的CRUD方法,首先在通用模块编写广告服务接口:
// 广告服务
public interface CategoryService {
// 增加广告
void add(Category category);
// 修改广告
void update(Category category);
// 修改广告状态
void updateStatus(Long id, Integer status);
// 删除广告
void delete(Long[] ids);
// 根据Id查询广告
Category findById(Long id);
// 分页查询广告
Page<Category> search(int page, int size);
// 查询全部启用广告
List<Category> findAll();
}
创建广告服务模块
1、创建名为 shopping_category_service 的SpringBoot工程,添加相关依赖。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- MyBatisPlus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.0</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.itbaizhan</groupId>
<artifactId>shopping_common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.8</version>
</dependency>
<!-- 操作zookeeper -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2、设置该工程的父工程为 shopping 。
<parent>
<groupId>com.ittxc</groupId>
<artifactId>shopping</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
3、给 shopping 工程设置子模块
<!-- 子模块 -->
<modules>
<!-- 广告服务 -->
<module>shopping_category_service</module>
</modules>
4、编写配置文件 application.yml
# 端口号
server:
port: 9004
# 日志格式
logging:
pattern:
console: '%d{HH:mm:ss.SSS} %clr(%-5level) --- [%-15thread] %cyan(%-50logger{50}):%msg%n'
# 配置Mybatis-plus
mybatis-plus:
global-config:
db-config:
# 表名前缀
table-prefix: bz_
# 主键生成策略为自增
id-type: auto
configuration:
# 关闭列名自动驼峰命名映射规则
map-underscore-to-camel-case: false
log-impl: org.apache.ibatis.logging.stdout.StdOutImp
l # 开启sql日志
spring:
# 数据源
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///baizhanshopping?serverTimezone=UTC
username: root
password01: 123456
dubbo:
application:
name: shopping_category_service # 项目名
registry:
address: zookeeper://192.168.100.131 #注册中心地址
port: 2181 # 注册中心端口号
timeout: 10000 # 注册到zk上超市时间,ms
protocol:
name: dubbo # dubbo使用的协议
port: -1 # 自动分配端口
scan:
base-packages: com.ittxc.shopping_category_service.service # 包扫描
5、启动类扫描Mapper包
@SpringBootApplication
@MapperScan("com.itbaizhan.shopping_category_service.mapper")
public class ShoppingCategoryServiceApplication {
public static void main(String[] args)
{
SpringApplication.run(ShoppingCategoryServiceApplication.class, args);
}
}
编写广告服务实现类
1、创建广告Mapper接口
public interface CategoryMapper extends BaseMapper<Category> { }
2、创建广告服务实现类
@DubboService
public class CategoryServiceImpl implements CategoryService {
@Autowired
private CategoryMapper categoryMapper;
@Override
public void add(Category category) {
categoryMapper.insert(category);
}
@Override
public void update(Category category)
{
categoryMapper.updateById(category);
}
@Override
public void updateStatus(Long id, Integer status) {
Category category = categoryMapper.selectById(id);
category.setStatus(status);
categoryMapper.updateById(category);
}
@Override
public Category findById(Long id) {
return categoryMapper.selectById(id);
}
@Override
public void delete(Long[] ids) {
categoryMapper.deleteBatchIds(Arrays.asList(ids));
}
@Override
public Page<Category> search(int page, int size) {
return categoryMapper.selectPage(new Page(page,size),null);
}
@Override
public List<Category> findAll() {
// 从数据库查询所有启用的广告
QueryWrapper<Category> queryWrapper = new QueryWrapper();
queryWrapper.eq("status",1);
List<Category> categories = categoryMapper.selectList(queryWrapper);
return categories;
}
}
编写广告管理控制器
1、在管理员Api模块编写广告管理控制器
/**
* 广告
*/
@RestController
@RequestMapping("/category")
public class CategoryController {
@DubboReference
private CategoryService categoryService;
/**
* 分页查询广告
*
* @param page 页码
* @param size 每页条数
* @return 查询结果
*/
@GetMapping("/search")
public BaseResult<Page<Category>> search(int page, int size) {
Page<Category> page1 = categoryService.search(page, size);
return BaseResult.ok(page1);
}
/**
* 增加广告
*
* @param category 广告对象
* @return 操作结果
*/
@PostMapping("/add")
public BaseResult add(@RequestBody Category category) {
categoryService.add(category);
return BaseResult.ok();
}
/**
* 修改广告
*
* @param category 广告对象
* @return 操作结果
*/
@PutMapping("/update")
public BaseResult update(@RequestBody Category category) {
categoryService.update(category);
return BaseResult.ok();
}
/**
* 修改广告状态
*
* @param id 广告id
* @param status 广告状态 0:未启用 1:启用
* @return 操作结果
*/
@PutMapping("/updateStatus")
public BaseResult updateStatus(Long id, Integer status) {
categoryService.updateStatus(id,status);
return BaseResult.ok();
}
/**
* 根据Id查询广告
*
* @param id 广告id
* @return 查询结果
*/
@GetMapping("/findById")
public BaseResult<Category> findById(Long id) {
Category category = categoryService.findById(id);
return BaseResult.ok(category);
}
/**
* 删除广告
*
* @param ids 广告id集合
* @return 操作结果
*/
@DeleteMapping("/delete")
public BaseResult delete(Long[] ids) {
categoryService.delete(ids);
return BaseResult.ok();
}
}
创建广告用户Api模块
前台用户在访问首页的时候是可以查看广告的,但前台项目无法使 用后台项目的接口,因为后台项目接口需要管理员登录才能使用, 且前台项目访问量大,我们需要专门编写一个api模块方便前台用户访问。
1、创建名为 shopping_category_customer_api 的SpringBoot工程,添加相关依赖。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.8</version>
</dependency>
<!-- 操作zookeeper -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>com.ittxc</groupId>
<artifactId>shopping_common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2、设置该工程的父工程为 shopping 。
<parent>
<groupId>com.ittxc</groupId>
<artifactId>shopping</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
3、给 shopping 工程设置子模块
<!-- 子模块 -->
<modules>
<!-- 网站用户操作广告暴露的api -->
<module>shopping_category_customer_api</module>
</modules>
4、编写配置文件 application.yml
# 端口号
server:
port: 8002
# 日志格式
logging:
pattern:
console: '%d{HH:mm:ss.SSS} %clr(%-5level) --- [%-15thread] %cyan(%-50logger{50}):%msg%n'
dubbo:
application:
name: shopping_category_customer_api #项目名
registry:
address: zookeeper://192.168.100.131 #注册中心地址
port: 2181 # 注册中心的端口
timeout: 10000 # 注册到zk上超时时间,ms
protocol:
name: dubbo # dubbo使用的协议
port: -1 # dubbo自动分配端口
5、启动类忽略数据源自动配置
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
public class ShoppingCategoryCustomerApiApplication {
public static void main(String[] args)
{
SpringApplication.run(ShoppingCategoryCustomerApiApplication.class, args);
}
}
6、编写前台用户广告控制器
/**
* 广告
*/
@RestController
@RequestMapping("/user/category")
public class CategoryController {
@DubboReference
private CategoryService categoryService;
/**
* 查询全部启用广告
*
* @return 查询结果
*/
@GetMapping("/all")
public BaseResult<List<Category>> findAll() {
List<Category> categories = categoryService.findAll();
return BaseResult.ok(categories);
}
}
7、启动前端客户端项目,测试前台查询广告接口
使用缓存优化用户查询广告
在用户访问网站首页时,需要查询网站的所有启用广告。而电商网 站用户访问量大,大量用户每次访问首页都从数据库查询广告非常 浪费资源,我们可以使用Redis缓存技术优化用户对于广告的查询。 思路如下:
安装Redis
1、安装GCC
yum install -y gcc
2、使用rz上传Redis压缩文件
3、解压并安装Redis
# 解压Redis
tar -zxvf redis-6.2.6.tar.gz -C /usr/local
# 进入Redis解压目录
cd /usr/local/redis-6.2.6/src/
# 编译Redis
make
# 安装Redis
make install
4、启动Redis
# 启动Redis,关闭保护状态
./redis-server --protected-mode no
优化广告服务实现类
1、在广告服务模块添加redis起步依赖
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-dataredis</artifactId>
</dependency>
2、在yml文件中配置redis连接
spring:
# 数据源
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///baizhanshopping?serverTimezone=UTC
username: root
password01: 123456
# redis
redis:
host: 192.168.100.131
port: 6379
timeout: 30000
jedis:
pool:
max-idle: 8
max-wait: -1
max-active: 8
min-idle: 0
3、修改广告服务实现类
@DubboService
public class CategoryServiceImpl
implements CategoryService {
@Autowired
private CategoryMapper categoryMapper;
// 对象名必须叫redisTemplate,否则由于容器中有多个RedisTemplate对象造成无法注入
@Autowired
private RedisTemplate redisTemplate;
@Override
public void add(Category category) {
categoryMapper.insert(category);
refreshRedisCategory();
}
@Override
public void update(Category category){
categoryMapper.updateById(category);
refreshRedisCategory();
}
@Override
public void updateStatus(Long id,Integer status) {
Category category = categoryMapper.selectById(id);
category.setStatus(status);
categoryMapper.updateById(category);
refreshRedisCategory();
}
@Override
public void delete(Long[] ids) {
categoryMapper.deleteBatchIds(Arrays.asList(ids));
}
@Override
public Category findById(Long id) {
return categoryMapper.selectById(id);
}
@Override
public Page<Category> search(int page,int size) {
return categoryMapper.selectPage(new Page(page,size),null);
}
@Override
public List<Category> findAll() {
// 1.从redis中查询启用的广告
// 1.1 获取操作redis中list数据的对象
ListOperations<String,Category> listOperations = redisTemplate.opsForList();
// 1.2 从redis中获取所有启用的广告
List<Category> categoryList = listOperations.range("categories", 0, -1);
if (categoryList != null && categoryList.size() > 0){
// 2.如果查到结果,直接返回
System.out.println("从redis中查询广告");
return categoryList;
}else{
// 3.如果redis中没有数据,则从数据库查询广告,并同步到redis中
System.out.println("从mysql中查询广告");
// 从数据库查询广告
QueryWrapper<Category> queryWrapper = new QueryWrapper();
queryWrapper.eq("status",1);
List<Category> categories = categoryMapper.selectList(queryWrapper);
// 同步到redis中
listOperations.leftPushAll("categories",categories);
return categories;
}
}
/**
* 更新redis中的广告数据
*/
public void refreshRedisCategory(){
// 从数据库查询广告
QueryWrapper<Category> queryWrapper = new QueryWrapper();
queryWrapper.eq("status",1);
List<Category> categories = categoryMapper.selectList(queryWrapper);
// 删除redis中的原有广告数据
redisTemplate.delete("categories");
// 将新的广告数据同步到redis中
ListOperations<String,Category> listOperations = redisTemplate.opsForList();
listOperations.leftPushAll("categories",categories);
}
}