说明:根据itemId和userId删除购物车
/**
* 业务:删除购物车操作
* url地址: http://www.jt.com/cart/delete/562379.html
* 参数问题: 562379
* 返回值结果: 重定向到购物车列表页面
*/
@RequestMapping("delete/{itemId}")
public String deleteCart(@PathVariable Long itemId) {
Long userId = 7L;
Cart cart = new Cart();
cart.setUserId(userId);
cart.setItemId(itemId);
cartService.deleteCart(cart);
return "redirect:/cart/show.html"; //维护伪静态策略
}
@Override
public void deleteCart(Cart cart) {
//让对象中不为null的属性充当where条件
QueryWrapper<Cart> queryWrapper = new QueryWrapper<>(cart);
cartMapper.delete(queryWrapper);
}
当用户未登录时,不允许访问敏感操作. 例如访问购物车/订单等系统.如何实现???
技术: 拦截器技术. shiro
说明:拦截器一般只拦截web页面资源的请求.
拦截器处理的流程图:
@Configuration
public class MvcConfigurer implements WebMvcConfigurer{
@Autowired
private UserInterceptor userInterceptor;
//开启匹配后缀型配置
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(true);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// /** 表示拦截多级目录 /* 只拦截一级目录
registry.addInterceptor(userInterceptor)
.addPathPatterns("/cart/**","/order/**");
}
}
@Component //将对象交给容器管理
public class UserInterceptor implements HandlerInterceptor{
@Autowired
private JedisCluster jedisCluster;
/**
* 目的: 如果用户不登录,则不允许访问权限相关业务.
* 返回值:
* true:表示放行
* false: 表示拦截 一般配置重定向使用.
* 注意事项:必须添加拦截器策略.
* 业务说明:
* 用户如果已经登录,则放行,反正拦截
*
* 如何判断用户是否登录:
* 1.判断客户端是否有指定的Cookie true
* 2.应该获取cookie中的值 去redis中校验是否存在. true
* 如果上述条件都满足,则应该放行请求.
*
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//业务实现 1.获取cookie
Cookie[] cookies = request.getCookies();
if(cookies !=null && cookies.length>0) {
for (Cookie cookie : cookies) {
if("JT_TICKET".equals(cookie.getName())){
//如果equals则说明cookie是存在的.
String ticket = cookie.getValue();
//2.redis中是否有该记录 如果有记录则放行请求.
if(jedisCluster.exists(ticket)) {
//说明数据以及存在.可以放行
return true;
}
}
}
}
//重定向到用户登录页面
response.sendRedirect("/user/login.html");
return false;
}
}
package com.jt.interceptor;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import com.jt.pojo.User;
import com.jt.util.ObjectMapperUtil;
import redis.clients.jedis.JedisCluster;
//mvc提供的对外的拦截器接口.
@Component //将对象交给容器管理
public class UserInterceptor implements HandlerInterceptor{
@Autowired
private JedisCluster jedisCluster;
/**
* 目的: 如果用户不登录,则不允许访问权限相关业务.
* 返回值:
* true:表示放行
* false: 表示拦截 一般配置重定向使用.
* 注意事项:必须添加拦截器策略.
* 业务说明:
* 用户如果已经登录,则放行,反正拦截
*
* 如何判断用户是否登录:
* 1.判断客户端是否有指定的Cookie true
* 2.应该获取cookie中的值 去redis中校验是否存在. true
* 如果上述条件都满足,则应该放行请求.
*
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//业务实现 1.获取cookie
Cookie[] cookies = request.getCookies();
if(cookies !=null && cookies.length>0) {
for (Cookie cookie : cookies) {
if("JT_TICKET".equals(cookie.getName())){
//如果equals则说明cookie是存在的.
String ticket = cookie.getValue();
//2.redis中是否有该记录 如果有记录则放行请求.
if(jedisCluster.exists(ticket)) {
//3.动态获取用户json信息
String userJSON = jedisCluster.get(ticket);
User user = ObjectMapperUtil.toObject(userJSON, User.class);
//利用request对象传递用户信息.
request.setAttribute("JT_USER", user);
//说明数据以及存在.可以放行
return true;
}
}
}
}
//重定向到用户登录页面
response.sendRedirect("/user/login.html");
return false;
}
}
说明:http://www.jt.com/order/create.html 当用户点击提交订单时.应该跳转到订单确认页面.之后添加收件人信息.
订单确认页面名称:order-cart.jsp
@Controller
@RequestMapping("/order")
public class OrderController {
@Reference(check = false)
private DubboCartService cartService;
/**
* 跳转到订单确认页面 http://www.jt.com/order/create.html
* 业务逻辑: 根据userId,之后查询购物车记录信息.之后在页面中展现购物车数据.
* 页面取值: ${carts}
*/
@RequestMapping("/create")
public String create(HttpServletRequest request,Model model) {
User user = (User) request.getAttribute("JT_USER");
long userId = user.getId();
List<Cart> cartList = cartService.findCartListByUserId(userId);
model.addAttribute("carts", cartList);
return "order-cart";
}
}
说明:从课前资料中导入pojo对象 导入到jt-common中.
1).创建项目
2).选择jar包文件
3).添加依赖/ 继承 /插件
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.jt.vip</groupId>
<artifactId>jt</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>jt-order</artifactId>
<!--添加依赖 -->
<dependencies>
<dependency>
<groupId>com.jt.vip</groupId>
<artifactId>jt-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<!--3.添加插件 -->
<!--负责项目打包 更新 maven操作相关的配置 必须添加 -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
server:
port: 8095
servlet:
context-path: /
spring:
datasource:
#driver-class-name: com.mysql.jdbc.Driver
#如果需要项目发布,则数据库地址必须配置远程数据库
url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
username: root
password: root
#配置视图解析器
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
#mybatis-plush配置
mybatis-plus:
type-aliases-package: com.jt.pojo
mapper-locations: classpath:/mybatis/mappers/*.xml
configuration:
map-underscore-to-camel-case: true
#日志记录 输出数据库的日志信息.
logging:
config: classpath:logging-config.xml
level:
com.jt.mapper: debug
dubbo:
scan:
basePackages: com.jt #指定dubbo的包路径
application:
name: provider-order #指定服务名称(必须指定)
registry:
address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183
protocol: #指定协议
name: dubbo #使用dubbo协议(tcp-ip) web-controller直接调用sso-Service
port: 20883 #每个服务都应该有自己特定的端口
html页面信息:
<html>
<input id="name" name="name"/>
<input id="age" name="age"/>
</html>
UserController后端接收:
利用request对象的取值和赋值的方式实现操作
public xxxxx saveUser(String name,Integer age){
}
<html>
<input id="name" name="name"/>
<input id="age" name="age"/>
</html>
UserController后端接收:
1.利用request对象取赋值操作. 2.利用对象的set方法,为对象的属性赋值.
public xxxxx saveUser(User user){
}
说明:如果按照下列的方式提交.,则会出现重名提交的问题.
解决方案: 可以利用为对象的引用赋值的操作.
<html>
<input id="name" name="name"/>
<input id="age" name="age"/>
<input id="name" name="dog.name" value="哮天犬"/>
<input id="age" name="dog.age" value="3"/>
</html>
UserController后端接收:
public class User{
private String name;
private Integer age;
private Dog dog; //对象的引用.
}
public class Dog{
private String name;
private Integer age;
}
//利用;User对象实现了User的数据与Dog的数据的获取.
public xxxxx saveUser(User user){
}
/**
* 1.url地址:http://www.jt.com/order/submit
* 2.参数 form表单提交
* 3.返回值 SysResult对象 并且包含orderId数据
* @return
*/
@RequestMapping("/submit")
@ResponseBody
public SysResult saveOrder(Order order,HttpServletRequest request) {
User user = (User) request.getAttribute("JT_USER");
Long userId = user.getId();
order.setUserId(userId); //将userId进行赋值操作.
String orderId = orderService.saveOrder(order);
if(StringUtils.isEmpty(orderId)) {
//说明:后端服务器异常
return SysResult.fail();
}
return SysResult.success(orderId);
}
@Service
public class OrderServiceImpl implements DubboOrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderShippingMapper orderShippingMapper;
@Autowired
private OrderItemMapper orderItemMapper;
@Transactional //控制事务.
@Override
public String saveOrder(Order order) {
String orderId = ""+order.getUserId() + System.currentTimeMillis();
Date date = new Date();
//1.实现订单入库
order.setOrderId(orderId)
.setStatus(1) //未付款
.setCreated(date)
.setUpdated(date);
orderMapper.insert(order);
System.out.println("订单入库成功!!!");
//2.订单物流入库
OrderShipping orderShipping = order.getOrderShipping();
orderShipping.setOrderId(orderId)
.setCreated(date)
.setUpdated(date);
orderShippingMapper.insert(orderShipping);
System.out.println("订单物流入库成功!!!!");
//3.订单商品入库
List<OrderItem> list = order.getOrderItems();
for (OrderItem orderItem : list) {
orderItem.setOrderId(orderId)
.setCreated(date)
.setUpdated(date);
orderItemMapper.insert(orderItem);
}
System.out.println("订单商品入库成功!!!!");
return orderId;
}
}
//http://www.jt.com/order/success.html?id=111595833611692
//获取order对象信息 ${order.orderId}
@RequestMapping("success")
public String findOrderById(String id,Model model) {
Order order = orderService.findOrderById(id);
model.addAttribute("order", order);
return "success";
}
@Override
public Order findOrderById(String orderId) {
Order order = orderMapper.selectById(orderId);
OrderShipping orderShipping = orderShippingMapper.selectById(orderId);
QueryWrapper<OrderItem> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("order_id", orderId);
List<OrderItem> orderItems = orderItemMapper.selectList(queryWrapper);
return order.setOrderShipping(orderShipping).setOrderItems(orderItems);
}
如果用户下单之后,30分钟之后如果还没有完成支付功能.则应该将订单的state 由1改为6
如何实现:
思路1: 在订单成功页面添加时钟. 规定三十分钟之后订单超时,之后发起ajax请求 设定订单状态!!! (表象) 糊弄鬼的 除非引入消息队列机制.
思路2: 在数据库中添加一个超时事件 如果数据库发现时间已经到了超时时间,则触发sql语句. 更新!!!
思路3: 准备一个单独的线程 该线程每隔1分钟 查询一次数据库是否有超时记录.如果有则批量修改.
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标准的Java组件或 EJBs。Quartz的最新版本为Quartz 2.3.2。
理解: Quartz 可以开启线程周期性的执行某个任务.
组件3大部分
1.调度器 2.负责管理/运行任务的组件
2.触发器 3. 当调度器发现程序要执行时,则通过触发器去实现页面调用.
3.job/jobDetail 1.自定义任务,之后需要设定任务的执行时间,需要将job封装为jobDetail.主要的目的提供 API.
<!--添加Quartz的支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
@Configuration
public class OrderQuartzConfig {
//定义任务详情 JobDetail封装job任务.
@Bean
public JobDetail orderjobDetail() {
//指定job的名称和持久化保存任务
return JobBuilder
.newJob(OrderQuartz.class) //1.任务的类型
.withIdentity("orderQuartz") //2.任务名称
.storeDurably()
.build();
}
//springBoot会实现对象的自动装配 开箱即用的功能.
//定义触发器 告知将来执行的任务是谁?
@Bean
public Trigger orderTrigger() {
/*SimpleScheduleBuilder builder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMinutes(1) //定义时间周期
.repeatForever();*/
//设定程序1分钟执行一次...
CronScheduleBuilder scheduleBuilder
= CronScheduleBuilder.cronSchedule("0 0/1 * * * ?");
return TriggerBuilder
.newTrigger()
.forJob(orderjobDetail()) //执行什么样的任务 *
.withIdentity("orderQuartz") //任务名称 *
.withSchedule(scheduleBuilder).build(); //什么时候执行
}
}
//准备订单定时任务
@Component
public class OrderQuartz extends QuartzJobBean{
@Autowired
private OrderMapper orderMapper;
/**
* 删除30分钟之后没有支付的订单,将状态由1改为6
* 业务实现:
* 如何判断超时: create < now -30分钟
* 1.sql update tb_order set status=6,updated=now() where status = 1 and
*/
@Override
@Transactional
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
//1.计算超时时间
Calendar calendar = Calendar.getInstance(); //获取当前时间
calendar.add(Calendar.MINUTE, -30);
Date timeOut = calendar.getTime(); //获取时间
//2.实现数据库更新
orderMapper.updateStatus(timeOut);
System.out.println("定时任务执行成!!!!!!"); //1分钟执行一次
}
}
1.修改数据库连接地址
2.修改图片地址
3.修改Linux中的nginx配置 之后重启服务器
4.修改HOSTS文件
说明:nginx服务器部署在129的服务器.所以需要都指向129
5.启动jt-manage nohup java -jar jt-manage.war -> jt-manage.log &
6.效果测试
1).修改数据库连接地址
2).打包发布 上传到130服务中. 位置如下
3).部署JDK
4).启动jt-sso项目
5).项目访问测试
6).nginx反向代理配置 修改完成之后重启nginx
#配置图片服务器
server {
listen 80;
server_name image.jt.com;
location / {
#配置反向代理的路径
root /usr/local/src/images;
}
}
#配置域名代理
server {
listen 80;
server_name manage.jt.com;
location / {
#代理tomcat服务器
proxy_pass http://tomcats;
}
}
#配置tomcat集群 默认是轮询策略
upstream tomcats {
proxy_pass http://192.168.126.129:8091;
#server localhost:8082;
#server localhost:8083;
}
server {
listen 80;
server_name sso.jt.com;
location / {
#代理tomcat服务器
proxy_pass http://192.168.126.130:8093;
}
}