乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      項目實(shí)戰(zhàn)

       Levy_X 2017-10-12
      導(dǎo)語:
        現(xiàn)在可以開始項目實(shí)戰(zhàn)開發(fā)了,關(guān)于項目搭建就是普通的springboot項目搭建,數(shù)據(jù)庫需要注意的問題就是字段屬性要設(shè)置正確,比如金額就要用BigDecimal而字段值就要用32、64、128的倍數(shù)設(shè)置更好。
        項目目錄:
        還是按照傳統(tǒng)的三層結(jié)構(gòu):Controller、Service、Dao(repository)編寫代碼,我們這里按照從底往上的順序進(jìn)行編寫并以O(shè)rder類的操作為例,首先開發(fā)Dao層
        Dao層
        我們這里采用的是JPA的方式操作數(shù)據(jù)庫
        /** * 查找訂單詳情 * Created by KHM * 2017/7/27 9:59 */public interface OrderDetailRepository extends JpaRepository{ List findByOrderId(String orderId);}1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        Service層接口和Impl
        /** * 訂單service層 * Created by KHM * 2017/7/27 11:04 */public interface OrderService { //創(chuàng)建訂單 OrderDTO create(OrderDTO orderDTO); //查詢單個訂單詳情 OrderDTO findOne(String orderId); //查詢訂單總列表(買家用) Page findList(String buyerOpenid, Pageable pageable); //取消訂單 OrderDTO cancel(OrderDTO orderDTO); //完結(jié)訂單 OrderDTO finish(OrderDTO orderDTO); //支付訂單 OrderDTO paid(OrderDTO orderDTO); //查詢訂單列表(賣家管理系統(tǒng)用的) Page findList(Pageable pageable);}1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        /** * Created by KHM * 2017/7/27 11:28 */@Service@Slf4jpublic class OrderServiceImpl implements OrderService { @Autowired private ProductService productService; @Autowired private OrderDetailRepository orderDetailRepository; @Autowired private OrderMasterRepository orderMasterRepository; @Autowired private PayService payService; @Autowired private WebSocket webSocket; @Override @Transactional//事務(wù)管理,一旦失敗就回滾 public OrderDTO create(OrderDTO orderDTO) { //設(shè)置下訂單id(是個隨機(jī),這里調(diào)用了根據(jù)時間產(chǎn)生6位隨機(jī)數(shù)的方法) String orderId = KeyUtil.genUniqueKey(); //給總價賦值 BigDecimal orderAmount = new BigDecimal(BigInteger.ZERO); //List cartDTOList = new ArrayList<>(); //1.查詢商品(數(shù)量,價格) for (OrderDetail orderDetail : orderDTO.getOrderDetailList()){ ProductInfo productInfo = productService.findOne(orderDetail.getProductId()); if(productInfo == null){ throw new SellException(ResultEnum.PRODUCT_NOT_EXIST); } //2.計算總價=單價*數(shù)量 orderAmount orderAmount = productInfo.getProductPrice() .multiply(new BigDecimal(orderDetail.getProductQuantity())) .add(orderAmount); //3.訂單詳情入庫(OrderMaster和orderDetail) //利用BeanUtils方法把前端查找出來的productInfo商品信息復(fù)制給訂單詳情 BeanUtils.copyProperties(productInfo, orderDetail);//先復(fù)制,再賦值 orderDetail.setDetailId(KeyUtil.genUniqueKey()); orderDetail.setOrderId(orderId); orderDetailRepository.save(orderDetail); /* CartDTO cartDTO = new CartDTO(orderDetail.getProductId(), orderDetail.getProductQuantity()); cartDTOList.add(cartDTO);*/ } //3.訂單總表入庫(OrderMaster和orderDetail) OrderMaster orderMaster = new OrderMaster(); orderDTO.setOrderId(orderId); BeanUtils.copyProperties(orderDTO, orderMaster); orderMaster.setOrderAmount(orderAmount);//是一個整個訂單的總價,所以在foe循環(huán)之外設(shè)置 orderMaster.setOrderStatus(OrderStatusEnum.New.getCode()); orderMaster.setPayStatus(PayStatusEnum.WAIT.getCode()); orderMasterRepository.save(orderMaster); //4.扣庫存 List cartDTOList = orderDTO.getOrderDetailList().stream().map(e -> new CartDTO(e.getProductId(), e.getProductQuantity()) ).collect(Collectors.toList()); productService.decreaseStock(cartDTOList); //發(fā)送websocket消息 webSocket.sendMessage(orderDTO.getOrderId()); return orderDTO; }1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74
        75
        76
        這里需要注意的問題主要是Impl層邏輯的編寫,我們需要用到的注解有:
        @Service
        @Slf4j日志需要
        @Transactional//事務(wù)管理,一旦失敗就回滾(主要用在要對數(shù)據(jù)庫進(jìn)行操作的方法上)
        然后是一些技巧:善于使用工具類做開發(fā),當(dāng)需要例如隨機(jī)數(shù)或者特殊字段的時候最好聲明在方法開始,方便之后的調(diào)用
        多多關(guān)注java的新特性,對代碼的優(yōu)化很有幫助
        最重要的,寫一個方法前先對這個方法的邏輯做個列舉,第一步是什么、第二步是什么,再去編寫具體的代碼
        Controller層
        /** * 購買操作 * Created by KHM * 2017/7/30 16:48 */@RestController@RequestMapping('/buyer/order')@Slf4jpublic class BuyerOrderController { @Autowired private OrderService orderService; @Autowired private BuyerService buyerService; //創(chuàng)建訂單 @PostMapping(value = '/create') public ResultVO> creat(@Valid OrderForm orderForm, BindingResult bindingResult){ if(bindingResult.hasErrors()){ log.error('【創(chuàng)建訂單】 參數(shù)不正確, orderForm={}', orderForm); throw new SellException(ResultEnum.PARAM_ERROR.getCode(), bindingResult.getFieldError().getDefaultMessage()); } OrderDTO orderDTO = OrderFormZOrderDTOConverter.convert(orderForm); if(CollectionUtils.isEmpty(orderDTO.getOrderDetailList())){ log.error('【創(chuàng)建訂單】 購物車不能為空'); throw new SellException(ResultEnum.CART_EMPTY); } OrderDTO createResult = orderService.create(orderDTO); Map map = new HashMap<>(); map.put('orderId', createResult.getOrderId()); return ResultVOUtil.success(map); } //訂單列表 @GetMapping(value = '/list') public ResultVO> list(@RequestParam('openid') String openid, @RequestParam(value = 'page', defaultValue = '0') Integer page, @RequestParam(value = 'size', defaultValue = '10') Integer size){ if(StringUtils.isNullOrEmpty(openid)){ log.error('【查詢訂單列表】 openid為空'); throw new SellException(ResultEnum.PARAM_ERROR); } PageRequest request = new PageRequest(page, size); Page orderDTOPage = orderService.findList(openid, request); //只用返回當(dāng)前頁面的數(shù)據(jù)集合就行了,因為前端傳過來的就是第幾頁和每一頁的size(一般都會定好) return ResultVOUtil.success(orderDTOPage.getContent()); } //訂單詳情 @GetMapping('/detail') public ResultVO detail(@RequestParam('openid') String openid, @RequestParam('orderId') String orderId){ /* //TODO 不安全的做法,改進(jìn) OrderDTO orderDTO = orderService.findOne(orderId);*/ OrderDTO orderDTO = buyerService.findOrderOne(openid, orderId); return ResultVOUtil.success(orderDTO); } //取消訂單 @PostMapping('/cancel') public ResultVO cancel(@RequestParam('openid') String openid, @RequestParam('orderId') String orderId){ /* //TODO 不安全的做法,改進(jìn) OrderDTO orderDTO = orderService.findOne(orderId); orderService.cancle(orderDTO);*/ buyerService.cancelOrder(openid, orderId); return ResultVOUtil.success(); }}1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74
        75
        76
        77
        Controller需要注意的問題是:
        請求方式一定要寫清楚Post和Get不要弄錯了
        需要前端做表單驗證的時候就要用@Valid 前端表單類
        做好幾乎所有的出現(xiàn)null或者錯誤的if判斷去拋出異常
        返回要用包裝類VO去返回
        關(guān)于Exception、幾種包裝類、工具類的介紹
        一般情況下有兩種注冊異常類的方法:
        /** * Created by KHM * 2017/7/27 17:34 */@Getterpublic class SellException extends RuntimeException { private Integer code; public SellException(ResultEnum resultEnum) { //把枚舉中自己定義的message傳到父類的構(gòu)造方法里,相當(dāng)于覆蓋message super(resultEnum.getMessage()); this.code = resultEnum.getCode(); } //而這個是需要自己去填寫code的新的meg,不一定是枚舉中的模糊的說法,可以把具體的錯誤信息信使出來 public SellException(Integer code, String message) { super(message); this.code = code; }}1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        善用工具類,反正只要是能單獨(dú)拆分出來使代碼看上去更優(yōu)雅的代碼都可以單獨(dú)寫出來當(dāng)做工具類
        包裝類:但凡是需要把原dataobject(數(shù)據(jù)庫對應(yīng)的實(shí)體類)組合或者拆分的新類我們都用包裝類來代替,可大致分為以下幾種包裝類:
        返回給前端的VO對象,主要按照前端API開發(fā)
        /** * 需要返回的商品詳情 * Created by KHM * 2017/7/26 17:54 */@Datapublic class ProductInfoVO implements Serializable { private static final long serialVersionUID = -3013889380494680036L; //為了防止多個name造成混淆,所以要細(xì)起名,但為了和返回對象名一致,所以用這個注解 //其實(shí)也不是造成混淆,主要原因還是為了和原productId對象中屬性名一致并且為了和前端API一致,才要在這里起別名,讓他在返回時實(shí)例化成別的名字 @JsonProperty('id') private String productId; @JsonProperty('name') private String productName; @JsonProperty('price') private BigDecimal productPrice; @JsonProperty('description') private String productDescription; @JsonProperty('icon') private String productIcon;}1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        前端和后端都包裝的DTO對象,主要也是按照前端API開發(fā),但是這個和VO的區(qū)別是DTO包含了整個原始對象,而VO縮減了一些屬性
        /** * DTO類用來關(guān)聯(lián)dataobject中有聯(lián)系的類,比如創(chuàng)建訂單就需要訂單總表和訂單詳情表兩種數(shù)據(jù), * 所以就需要一種包含了這兩種實(shí)體的包裝類把他們聯(lián)系起來 * 因為用dataobject來關(guān)聯(lián)的話會破壞映射的數(shù)據(jù)庫的關(guān)系 * Created by KHM * 2017/7/27 11:10 */@Data//@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)//@JsonInclude(JsonInclude.Include.NON_NULL)//可以讓為null屬性不返回public class OrderDTO { //訂單id //@Id,不需要此注解了,因為這不是關(guān)聯(lián)數(shù)據(jù)庫的類 private String orderId; //買家姓名 private String buyerName; //買家手機(jī)號 private String buyerPhone; //買家地址 private String buyerAddress; //買家微信openid private String buyerOpenid; //訂單總金額 private BigDecimal orderAmount; //訂單狀態(tài),默認(rèn)為0新下單 private Integer orderStatus; //支付狀態(tài),默認(rèn)為0未支付 private Integer payStatus; //創(chuàng)建時間 @JsonSerialize(using = Date2LongSerializer.class) private Date createTime; //更新時間 @JsonSerialize(using = Date2LongSerializer.class) private Date updateTime; //@Transient//為了方便關(guān)聯(lián)訂單總表和詳情表,把此字段加在這.用此注解就可以讓程序在與數(shù)據(jù)庫關(guān)聯(lián)時忽略此字段,但是更規(guī)范的寫法就是創(chuàng)建新的DTO private List orderDetailList; //= new ArrayList<>();(配置中配置了如果為null就不返回) @JsonIgnore//在返回json的時候回忽略這個屬性 public OrderStatusEnum getOrderStatusEnum() { return EnumUtil.getByCode(orderStatus, OrderStatusEnum.class); } @JsonIgnore public PayStatusEnum getPayStatusEnum() { return EnumUtil.getByCode(payStatus, PayStatusEnum.class); }#配置了這個就不會返回為NULL的參數(shù) jackson: default-property-inclusion: non_null}1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        總結(jié):這些常規(guī)的后臺開發(fā)最主要要的問題在于邏輯,開發(fā)每一個方法前要先想清楚這個方法的步奏,怎樣寫最方便,什么時候該用到工具類,返回時要不要用包裝對象,時刻在可能出現(xiàn)錯誤的地方打上日志和拋出異常,單元測試一定要貫穿三層,Dao和Service層用Slf4j,Controller用Postman。這樣才能保證開發(fā)不會出問題找不到。
        微信支付篇:http://blog.csdn.net/qq_31783173/article/details/77618374
        關(guān)于FreeMarker ibootstrap ModelAndView
        假如你是個后端人員又需要自己寫后臺管理界面的時候,這套組合可謂是快速開發(fā)的神器了,用ibootstrap完成html代碼的實(shí)現(xiàn),放在FreeMarker中,不用AJAX即可完成數(shù)據(jù)的交互,詳情請查看FreeMarker:?
        用分布式Session完成用戶信息的登錄判斷
        什么是分布式系統(tǒng):
        旨在支持應(yīng)用程序和服務(wù)的開發(fā),可以利用物理架構(gòu)由多個自治的處理元素,不共享主內(nèi)存,但通過網(wǎng)絡(luò)發(fā)送消息合作。 --Leslie Lamport
        三個特點(diǎn)和三個概念
        Session
        廣義的session:會話控制,不是普通的Http的Session
        可以理解為一種Key-value的機(jī)制
        它的關(guān)鍵點(diǎn)在于怎么設(shè)置Key和獲取對應(yīng)的value
        第一種:SessionId客戶端在請求服務(wù)端的時候,服務(wù)端會在Http的Header里面設(shè)置key和value,而客戶端的cookie會把這個保存,后續(xù)的請求里面會自動的帶上
        第二種:token,我們需要手動在Http的Header或Url里設(shè)置token這個字段,服務(wù)器獲得請求后在從Url或者Header里取出token進(jìn)行驗證,安全要求比較嚴(yán)格的時候需要配合簽名一起使用
        共同點(diǎn):區(qū)局唯一
        分布式系統(tǒng)中的session問題
        當(dāng)我們使用分布式系統(tǒng)運(yùn)行時,會有多臺服務(wù)器,怎么放呢?有兩種方式
        水平擴(kuò)展:就是在多臺服務(wù)器上部署一樣的程序,就是集群
        垂直擴(kuò)展:其實(shí)就是拆分服務(wù),不同Url負(fù)載均衡到不同的服務(wù)器上去
        然后,當(dāng)用戶進(jìn)行登錄時,第一次可能在A服務(wù)器上,第二次可能就跑到B服務(wù)器上了,B服務(wù)器沒有用戶的Session,就以為沒有登錄,IPHash的解決方案還是優(yōu)缺點(diǎn)不適用,真正的解決方案是什么呢?
        加一臺服務(wù)器裝上Redis來專門保存用戶的session信息,當(dāng)其他服務(wù)器需要session信息的時候都去找他要
        我們知道常規(guī)的登錄、登錄就是驗證信息,存儲瀏覽狀態(tài)和讓瀏覽狀態(tài)失效,我們這里使用的第二種:token的方式,自己設(shè)置一個token字段,然后手動添加到cookie中,還有失效時間;登出的時候先清除redis的token,之后我們在訪問其他頁面的時候就可以通過cookie和redis的驗證了,但這里似乎沒有做關(guān)閉瀏覽器清除session的設(shè)置,具體代碼實(shí)現(xiàn):
        /** * 賣家用戶登錄管理 * Created by Akk_Mac * Date: 2017/8/30 上午9:31 */@Controller@RequestMapping('/seller')public class SellerUserController { @Autowired private SellerService sellerService; //redis的service,這里主要用stringredis @Autowired private StringRedisTemplate redisTemplate; @Autowired private ProjectUrlConfig projectUrlConfig; @RequestMapping('/login') public ModelAndView login(@RequestParam(value = 'username', required=false ) String username, @RequestParam(value = 'password', required = false) String password, HttpServletResponse response, Map map) { //1. 由于我們這里沒有申請微信開放平臺,所以就不用掃碼登錄了 if(username == null && password == null){ return new ModelAndView('common/login'); } SellerInfo sellerInfo = sellerService.findSellerInfoByUsername(username); if(sellerInfo == null && !sellerInfo.getPassword().equals(password)) { map.put('msg', ResultEnum.LGOIN_FAIL.getMessage()); //map.put('url', '/sell/seller/order/list'); return new ModelAndView('common/login', map); } //2. 設(shè)置token至redis(用什么UUID設(shè)置) String token = UUID.randomUUID().toString(); Integer expire = RedisConstant.EXPIRE;//token過期時間 //(key:token_ 為開頭的格式String.format是格式設(shè)置方法, value=這里先設(shè)置為username, 過期時間, 時間單位) redisTemplate.opsForValue().set(String.format(RedisConstant.TOKEN_PREFIX, token), username, expire, TimeUnit.SECONDS); //3. 設(shè)置token至cookie CookieUtil.set(response, CookieConstant.TOKEN, token, expire); //這里不是跳轉(zhuǎn)到模板而是地址所以要用redirect,而且跳轉(zhuǎn)最好用絕對地址 return new ModelAndView('redirect:' projectUrlConfig.getSell() '/sell/seller/order/list'); } @RequestMapping('/logout') public ModelAndView logout(HttpServletRequest request, HttpServletResponse response, Map map) { //1. 從cookie中查詢 Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN); if(cookie != null) { //2. 清除redis redisTemplate.opsForValue().getOperations().delete(String.format(RedisConstant.TOKEN_PREFIX, cookie.getValue())); //3. 清除cookie CookieUtil.set(response, CookieConstant.TOKEN, null, 0); } map.put('msg', ResultEnum.LOGOUT_SUCCESS.getMessage()); map.put('url', '/sell/seller/login'); return new ModelAndView('common/success', map); }}1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        AOP切面編程
        /** * AOP切面編程驗證登錄 * Created by Akk_Mac * Date: 2017/8/30 上午11:05 */@Aspect@Component@Slf4jpublic class SellerAuthorizeAspect { @Autowired private StringRedisTemplate redisTemplate; //攔截除了登錄登出之外的操作,這是設(shè)置攔截范圍 @Pointcut('execution(public * com.akk.controller.Seller*.*(..))' '&& !execution(public * com.akk.controller.SellerUserController.*(..))') public void verify(){} @Before('verify()') public void doVerify() { ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); //1. 查詢Cookie Cookie cookie = CookieUtil.get(request, CookieConstant.TOKEN); if(cookie == null) { log.warn('【登錄校驗】Cookie中查不到token'); throw new SellerAuthorizeException(); } //2. 根據(jù)cookie查redis String tokenValue = redisTemplate.opsForValue().get(String.format(RedisConstant.TOKEN_PREFIX, cookie.getValue())); if(StringUtils.isEmpty(tokenValue)) { log.warn('【登錄校驗】Redis中查不到token'); throw new SellerAuthorizeException(); } }}1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        項目部署
        原本SpringBoot的部署是最好把項目打包成war包放在tomcat上,但我發(fā)現(xiàn),我這里用打war的方法,要去掉spring-boot-starter-web包中的內(nèi)置tomcat容器,這樣會使websocket類出現(xiàn)問題,檢測不到j(luò)avax包,試了幾次沒有辦法,就用了另一種方法,打成Jar包的形式,先用控制臺運(yùn)行的方式在服務(wù)器運(yùn)行,這樣是有點(diǎn)隱患的,但這個沖突還沒有解決。打jar包詳情見:http://blog.csdn.net/xiao__gui/article/details/47341385

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多