京淘后端商品管理-Day18

1.购物车操作

1.1 删除购物车

1.1.1编辑CartController

说明:根据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"; //维护伪静态策略
	}

1.1.2编辑CartService

@Override
	public void deleteCart(Cart cart) {
		
		//让对象中不为null的属性充当where条件
		QueryWrapper<Cart> queryWrapper = new QueryWrapper<>(cart);
		cartMapper.delete(queryWrapper);
	}

2.权限控制

2.1 业务需求说明

当用户未登录时,不允许访问敏感操作. 例如访问购物车/订单等系统.如何实现???
技术: 拦截器技术. shiro

2.2SpringMVC中拦截器定义

说明:拦截器一般只拦截web页面资源的请求.
拦截器处理的流程图:
京淘后端商品管理-Day18_第1张图片

2.3拦截器配置

	@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/**");
	}
}

2.4编辑拦截器业务

	@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;
	}
}

2.5 动态获取userId

说明:如何动态获取userId
京淘后端商品管理-Day18_第2张图片

2.5.1 动态获取User信息

	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;
	}
}

2.5.2 动态获取userId

京淘后端商品管理-Day18_第3张图片

3.订单确认页面跳转

3.1 订单业务说明

说明:http://www.jt.com/order/create.html 当用户点击提交订单时.应该跳转到订单确认页面.之后添加收件人信息.
订单确认页面名称:order-cart.jsp

3.2编辑OrderController

@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";
	}
	
}

3.3页面效果展现

京淘后端商品管理-Day18_第4张图片

4.订单业务结构表设计

4.1 表结构设计

京淘后端商品管理-Day18_第5张图片

4.2 导入订单pojo对象

说明:从课前资料中导入pojo对象 导入到jt-common中.
京淘后端商品管理-Day18_第6张图片

4.3 创建JT-ORDER项目

1).创建项目
京淘后端商品管理-Day18_第7张图片
2).选择jar包文件
京淘后端商品管理-Day18_第8张图片
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>

4).赋值jt-order的src文件即可
京淘后端商品管理-Day18_第9张图片

4.4 编辑YML配置文件

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 #每个服务都应该有自己特定的端口  

4.5 关于POJO主键的说明

说明:POJO中的主键只能有一个.
京淘后端商品管理-Day18_第10张图片

5.SpringMVC的页面与后端数据传递方式.

5.1 简单模式

html页面信息:

 						<html>
									<input  id="name" name="name"/>  
									<input  id="age" name="age"/>
						 </html>

UserController后端接收:
利用request对象的取值和赋值的方式实现操作

 		public xxxxx   saveUser(String name,Integer age){
 		
 		}

5.2 利用对象的方式封装

 						<html>
									<input  id="name" name="name"/>  
									<input  id="age" name="age"/>
						 </html>

UserController后端接收:
1.利用request对象取赋值操作. 2.利用对象的set方法,为对象的属性赋值.

 		public xxxxx   saveUser(User user){
 		
 		}

5.3 为对象的引入赋值

说明:如果按照下列的方式提交.,则会出现重名提交的问题.
解决方案: 可以利用为对象的引用赋值的操作.

 						<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){
 		
 }

5.4 京淘项目的应用案例

1.页面HTML标记
京淘后端商品管理-Day18_第11张图片
2.标识POJO 对象封装方式.
京淘后端商品管理-Day18_第12张图片

6.订单提交

6.1 页面分析

1.页面url分析
京淘后端商品管理-Day18_第13张图片
2.参数分析
京淘后端商品管理-Day18_第14张图片
3.页面Html标识
京淘后端商品管理-Day18_第15张图片

6.2 编辑OrderController

	/**
	 * 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);
	}

6.3 编辑OrderService

	@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;
	}
}

7 订单查询操作

7.1 业务说明

说明:当订单提交成功之后 需要展现订单成功页面
京淘后端商品管理-Day18_第16张图片

7.2 编辑OrderController

	//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";
	}

7.3 编辑OrderService

@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);
	}

7.4 页面效果展现

京淘后端商品管理-Day18_第17张图片

8 定时任务实现

8.1 业务说明

如果用户下单之后,30分钟之后如果还没有完成支付功能.则应该将订单的state 由1改为6
如何实现:
思路1: 在订单成功页面添加时钟. 规定三十分钟之后订单超时,之后发起ajax请求 设定订单状态!!! (表象) 糊弄鬼的 除非引入消息队列机制.
思路2: 在数据库中添加一个超时事件 如果数据库发现时间已经到了超时时间,则触发sql语句. 更新!!!
思路3: 准备一个单独的线程 该线程每隔1分钟 查询一次数据库是否有超时记录.如果有则批量修改.

8.2 Quartz介绍

Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标准的Java组件或 EJBs。Quartz的最新版本为Quartz 2.3.2。
理解: Quartz 可以开启线程周期性的执行某个任务.
京淘后端商品管理-Day18_第18张图片
组件3大部分
1.调度器 2.负责管理/运行任务的组件
2.触发器 3. 当调度器发现程序要执行时,则通过触发器去实现页面调用.
3.job/jobDetail 1.自定义任务,之后需要设定任务的执行时间,需要将job封装为jobDetail.主要的目的提供 API.

8.3 导入jar包

	<!--添加Quartz的支持 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-quartz</artifactId>
		</dependency>

8.4 编辑配置类

@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(); //什么时候执行
	}
}

8.5 编辑定时任务处理类

//准备订单定时任务
@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分钟执行一次
	}
}

9.京淘项目发布

京淘后端商品管理-Day18_第19张图片

9.1 服务器部署规划

  1. Linux 129 NGINX/ZK/REDIS/MYCAT/MYSQL-M/JT-MANAGE(图片回显)
  2. LINUX 130 JT-WEB/JT-SSO/JT-CART/JT-ORDER
    注意事项:将jt-common先打包处理

9.2 部署jt-manage

1.修改数据库连接地址
京淘后端商品管理-Day18_第20张图片
2.修改图片地址
京淘后端商品管理-Day18_第21张图片
3.修改Linux中的nginx配置 之后重启服务器
京淘后端商品管理-Day18_第22张图片
4.修改HOSTS文件
说明:nginx服务器部署在129的服务器.所以需要都指向129
京淘后端商品管理-Day18_第23张图片

5.启动jt-manage nohup java -jar jt-manage.war -> jt-manage.log &
6.效果测试
京淘后端商品管理-Day18_第24张图片

9.3 部署JT-SSO

1).修改数据库连接地址
京淘后端商品管理-Day18_第25张图片
2).打包发布 上传到130服务中. 位置如下
京淘后端商品管理-Day18_第26张图片

3).部署JDK
京淘后端商品管理-Day18_第27张图片
4).启动jt-sso项目
京淘后端商品管理-Day18_第28张图片
5).项目访问测试
京淘后端商品管理-Day18_第29张图片
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;

		}
	}

7).nginx测试
京淘后端商品管理-Day18_第30张图片

9.4 部署JT-CART/JT-ORDER

1.修改数据源配置
京淘后端商品管理-Day18_第31张图片
2.项目打包部署

9.5 部署JT-WEB

打包之后,直接部署即可.
命令: java -jar jt-web.war
京淘后端商品管理-Day18_第32张图片
京淘后端商品管理-Day18_第33张图片

你可能感兴趣的:(正课)