1. 程式人生 > >電商專案day06(繼承spring-security框架到商家管理&商家商品錄入)

電商專案day06(繼承spring-security框架到商家管理&商家商品錄入)

今日目標:

1、完成商家管理的安全框架控制

2、完成登入的密碼加密(BCrypt加密演算法)

3、商家登入登出的使用者名稱顯示

4、商品錄入功能實現之商品基本資訊錄入

一、商家管理加入安全框架

分析:在運營商管理的中我們,我們的使用者名稱和密碼都是在spring-srcurity.xml檔案中配置是寫死的,那麼我們在商家中,我們通過獲得使用者的資料庫密碼,來實現登入

1.首先匯入相關的mavenjar包

spring-security-web                spring-security-conf

2、匯入web.xml中的過濾器鏈,以及spring-security.xml問題(放行一些不需要攔截的資源)

<!-- 以下頁面不被攔截 -->
<http pattern="/css/**" security="none"></http>
<http pattern="/img/**" security="none"></http>
<http pattern="/js/**" security="none"></http>
<http pattern="/plugins/**" security="none"></http>
<http pattern="/shoplogin.html" security="none"></http>
<http pattern="/register.html" security="none"></http>
<!--不攔截方法-->
<http pattern="/selller/add.do" security="none"></http>

3、配置認證服務類,完成認證,授權工作

<!-- 認證管理器 -->
<authentication-manager>
   <!--自定義認證服務類-->
   <authentication-provider user-service-ref="userDetailService">
   </authentication-provider>
</authentication-manager>

<beans:bean id="userDetailService" class="com.pinyougou.user.service.UserDetailService"></beans:bean>

4、在shop的controller層,新增userService包下的userDetailServiceImpl   繼承 userDetailService

public class UserDetailService implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        //構建使用者許可權集合資料
        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("ROLE_SELLER"));
        //引數一:使用者名稱   引數二;密碼   許可權集合
        return  new User(username,"123456",authorities);
    }
}

注意我們在這一步先寫死密碼,等會我們在從資料庫中查

5.編寫shopindex.xml頁面

6.從資料庫中查詢密碼

分析:我們知道shop中dubbo掃描的是controller,而我們的包在user.service中,所以我們要通過配置類,來出入duboo,這樣才能用reference。

在userDetailService配置set方法

private SellerService sellerService;

public void setSellerService(SellerService sellerService) {
    this.sellerService = sellerService;
}

在配置檔案中配置

<!--認證服務類-->
<beans:bean id="userDetailService" class="com.pinyougou.user.service.UserDetailService">
   <beans:property name="sellerService" ref="sellerService"></beans:property>
   <!--name指的是  private SellerService sellerService;  中的SellerService
    應用的是下面的dubbo服務的id為sellerService
   -->
</beans:bean>

<!-- 引用dubbo 服務 -->
<dubbo:application name="pinyougou_shop_web" />
<dubbo:registry address="zookeeper://192.168.25.128:2181"/>
<dubbo:reference interface="com.pinyougou.sellergoods.service.SellerService" id="sellerService" />

注意:我們要在user.service中新增判斷

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    TbSeller tbSeller = sellerService.findOne(username);
    if (tbSeller!=null){
        //必須判斷狀態,只有稽核通過的狀態,才能正常登入
        if("1".equals(tbSeller.getStatus())){
            //構建使用者許可權集合資料
            List<GrantedAuthority> authorities = new ArrayList<>();
            authorities.add(new SimpleGrantedAuthority("ROLE_SELLER"));
            //引數一:使用者名稱   引數二;密碼   許可權集合
            return  new User(username,tbSeller.getPassword(),authorities);
        }else{
            return null;
        }

    }else {
        return null;
    }
}

7、密碼的加密行為,作為註冊是的密碼

分析:商家入駐密碼加密
        MD5  雜湊演算法,不可逆  加密長度:32位
        BCrypt 加鹽 123456  加密後的字串是60位
        123456 + 加鹽(隨機字串)

我們採用spring-security提供的加密演算法進行加密,注意在controller層完成,因為,在controller層才有spring-security的框架配置

<!-- 認證管理器 -->
<authentication-manager>
   <!--自定義認證服務類-->
   <authentication-provider user-service-ref="userDetailService">
      <!--基於passwordEncoding對登入傳輸的明文密碼進行加密-->
      <password-encoder ref="passwordEncoder"></password-encoder>
   </authentication-provider>
</authentication-manager>
<!--登入需要對輸入的密文及進行加密-->
<beans:bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></beans:bean>

登入的時候也通過bcryptPasswordEncoder加密

二、商家後臺商品錄入

商家的商品錄入有點,複雜,我們一共設計到八張表

    SPU: 標準生產單位                      例如:iPhone6s 
    SKU:最小庫存量單位  最小銷售單元       例如:金色、聯通4G、64G iphone6s
    SPU = Standard Product Unit (標準產品單位)
SPU 是商品資訊聚合的最小單位,是一組可複用、易檢索的標準化資訊的集合,該集合描述
了一個產品的特性。
通俗點講,屬性值、特性相同的商品就可以稱為一個 SPU。
例如:
iphone7 就是一個 SPU,與商家,與顏色、款式、套餐都無關。
SKU=stock keeping unit( 庫存量單位)
SKU 即庫存進出計量的單位, 可以是以件、盒、托盤等為單位。
SKU 是物理上不可分割的最小存貨單元。在使用時要根據不同業態,不同管理模式來處理。
在服裝、鞋類商品中使用最多最普遍。
    SPU 與SKU 是一對多關係。
            SPU:  iPhone6s    
            顏色:     金色  黑色  銀色
            機身記憶體:    64G  128G
            SKU:  
            金色、64G iphone6s
            黑色、64G iphone6s
            銀色、64G iphone6s
            
            金色、128G iphone6s
            黑色、128G iphone6s
            銀色、128G iphone6s
    
    一對多,誰維護關聯關係呢?
        多方維護
                                        
    商品表關係分析

商品相關表:
            SPU :tb_goods tb_goods_desc(是對tb_goods表的補充描述,作用:抽取大欄位內容到tb_goods_desc表,主要作用:提高資料查詢效能)
            SKU :tb_item
                
        商品間接相關屬性表:
        
        模板表  與商品表關係是 一對多
        分類表
        品牌表
        規格表
        規格選項表
        
        共8張表
        
        tb_goods tb_goods_desc  一對一
        tb_goods tb_item  spu對sku  一對多
        
        tb_brand tb_type_template  多對多
        tb_specification tb_type_template  多對多
        tb_item_cat tb_type_template  三級分類與模板關係  一對一
        tb_specification tb_specification_option  一對多
        
        tb_type_template  tb_goods  一對多 

我們在分析一下我們後臺和前臺要組裝的資料有哪些

tb_goods
          `is_delete` varchar(1) DEFAULT NULL COMMENT '是否刪除',
          
          邏輯刪除: 當is_delete=1,代表刪除狀態
            在資料庫表設計時,指定一個欄位記錄該條資料的刪除狀態。
            邏輯刪除就是更新刪除欄位狀態操作。
            
          
         頁面組裝的資料:
            `goods_name` varchar(100) DEFAULT NULL COMMENT 'SPU名',
            `brand_id` bigint(10) DEFAULT NULL COMMENT '品牌',
          `caption` varchar(100) DEFAULT NULL COMMENT '副標題',
          `category1_id` bigint(20) DEFAULT NULL COMMENT '一級類目',
          `category2_id` bigint(10) DEFAULT NULL COMMENT '二級類目',
          `category3_id` bigint(10) DEFAULT NULL COMMENT '三級類目',
          `price` decimal(10,2) DEFAULT NULL COMMENT '商城價',
           `type_template_id` bigint(20) DEFAULT NULL COMMENT '分類模板ID',
            `is_enable_spec` varchar(1) DEFAULT NULL COMMENT '是否啟用規格',
         
         
         後臺組裝的資料:
            `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
            `seller_id` varchar(20) DEFAULT NULL COMMENT '商家ID',  基於安全框架獲取
            `audit_status` varchar(2) DEFAULT NULL COMMENT '狀態',  新錄入商品都是未稽核 0
        
          
        tb_goods_desc
         後臺組裝的資料:
            `goods_id` bigint(20) NOT NULL COMMENT 'SPU_ID',
          
        頁面組裝的資料:
           `introduction` varchar(3000) DEFAULT NULL COMMENT '描述',
          `specification_items` varchar(3000) DEFAULT NULL COMMENT '規格結果集,所有規格,包含isSelected',
          `custom_attribute_items` varchar(3000) DEFAULT NULL COMMENT '自定義屬性(引數結果)',
          `item_images` varchar(3000) DEFAULT NULL,
          `package_list` varchar(3000) DEFAULT NULL COMMENT '包裝列表',
          `sale_service` varchar(3000) DEFAULT NULL COMMENT '售後服務',
        

1.首先第一步我們要把頁面的三張表的資料儲存到資料庫中,tb_goods,tb_goods_desc ,tb_item ,所以我們的準備工作是,複製運營商管理的三個到shop的controller中,如圖:

通過拷貝相對的前端controller和service

2.那我們要通過組裝資料到資料庫,就要建立已給實體類,來封裝這個三個表的資料

3、富文字編輯器

三個:

KindEditor http://kindeditor.net/
UEditor http://ueditor.baidu.com/website/
CKEditor http://ckeditor.com/ 

如何使用:   步驟:1.匯入資原始檔    2.編寫一個文字域textarea   3.獲取編輯好的hmtl標籤,提交到資料庫,頁面展示的時候,直接通過的html標籤展示,帶有樣式效果哦 

清空的富文字編輯器

editor.html('');//清空富文字編輯器

提取文字編輯器的內容

在 goodsController.js 中的 add()方法中新增
$scope.entity.goodsDesc.introduction=editor.html();

後臺程式碼實現:

通過controller層我們封裝商家的id,通過安全框架獲得,

service層我們就要分開新增,分別tbgoods和goodsDesc表,注意goodsDesc中的表的goods_id通過goods表獲得,tbgoods新增商品狀態為0

注意:非常重要的東西,一定要加事務,因為多張表,如果一張插入不成功,則回滾

核心程式碼:

@RequestMapping("/add")
	public Result add(@RequestBody Goods goods){
		try {
			//在這個我們組裝,商家的id,基於安全框架獲取
			String name = SecurityContextHolder.getContext().getAuthentication().getName();
			goods.getTbGoods().setSellerId(name);
			goodsService.add(goods);
			return new Result(true, "增加成功");
		} catch (Exception e) {
			e.printStackTrace();
			return new Result(false, "增加失敗");
		}
	}
//service
/**
	 * 增加
	 */
	@Override
	public void add(Goods goods) {
		//獲取goods表,我們在插入的時候獲取插入時的id,因為這個表關聯goodsDesc
		TbGoods tbGoods = goods.getTbGoods();
		goodsMapper.insert(tbGoods);

		//獲取goodsDesc表
		TbGoodsDesc tbGoodsDesc = goods.getTbGoodsDesc();
		tbGoodsDesc.setGoodsId(tbGoods.getId());
		goodsDescMapper.insert(tbGoodsDesc);

	}

前臺程式碼實現:

我們通過先修改service -》 controller-》頁面   先封裝也面有的,包括獲取富文字的html標籤

三級聯動通過  依賴angularjs監控機制實現。 $watch  

 //監控一級分類下的二級分類
	//引數一:監控的變數值,引數二:監控變化後,需要的做的事
	$scope.$watch("entity.tbGoods.category1Id",function (newValue,oldValue) {
        itemCatService.findByParentId(newValue).success(function (response) {
            $scope.itemCat2List=response;
        })
    })
    //監控二級分類下的三級分類
    //引數一:監控的變數值,引數二:監控變化後,需要的做的事
    $scope.$watch("entity.tbGoods.category2Id",function (newValue,oldValue) {
        itemCatService.findByParentId(newValue).success(function (response) {
            $scope.itemCat3List=response;
           //遺留的問題如何清理
        })
    })
    //監控三級分類下的模板id
    //引數一:監控的變數值,引數二:監控變化後,需要的做的事
    $scope.$watch("entity.tbGoods.category3Id",function (newValue,oldValue) {
        itemCatService.findOne(newValue).success(function (response) {
            $scope.entity.tbGoods.typeTemplateId=response.typeId;
            //遺留的問題如何清空三級的標題
        })
    })
    //監控模板下的查詢關聯資料
    //引數一:監控的變數值,引數二:監控變化後,需要的做的事
    $scope.$watch("entity.tbGoods.typeTemplateId",function (newValue,oldValue) {
        typeTemplateService.findOne(newValue).success(function (response) {
        	//注意一定要把品牌的json字串變為json物件
            $scope.brandList=JSON.parse(response.brandIds);

        })
    })

注意頁面記得匯入itemCatList和typeTemplaleList的前端service  的檔案

<td>
		                           	  				<select class="form-control" ng-model="entity.tbGoods.category1Id" ng-options="item.id as item.name for item in itemCat1List">
		                           	  				</select>
		                              			</td>
		                              			<td>
		                           	  				<select class="form-control select-sm" ng-model="entity.tbGoods.category2Id" ng-options="item.id as item.name for item in itemCat2List"></select>
		                              			</td>
		                              			<td>
		                           	  				<select class="form-control select-sm" ng-model="entity.tbGoods.category3Id" ng-options="item.id as item.name for item in itemCat3List"></select>
		                              			</td>
		                              			<td>
		                           	  				模板ID:{{entity.tbGoods.typeTemplateId}}
		                              			</td>



品牌:
<div class="col-md-2 title">品牌</div>
		                           <div class="col-md-10 data">
		                              <select class="form-control" ng-model="entity.tbGoods.brandId" ng-options="brand.id as brand.text for brand brandLiset" ></select>
		                           </div>

三、建立的錯誤

四、總結

$watch簡單使用

$watch是一個scope函式,用於監聽模型變化,當你的模型部分發生變化時它會通知你。

 

$watch(watchExpression, listener, objectEquality);

每個引數的說明如下:

  1. watchExpression:監聽的物件,它可以是一個angular表示式如'name',或函式如function(){return $scope.name}。

  2. listener:當watchExpression變化時會被呼叫的函式或者表示式,它接收3個引數:newValue(新值), oldValue(舊值), scope(作用域的引用)

  3. objectEquality:是否深度監聽,如果設定為true,它告訴Angular檢查所監控的物件中每一個屬性的變化. 如果你希望監控陣列的個別元素或者物件的屬性而不是一個普通的值, 那麼你應該使用它

  4.  舉個例子:這是監測一個屬性的變化

$scope.name = 'hello';

var watch = $scope.$watch('name',function(newValue,oldValue, scope){

        console.log(newValue);

        console.log(oldValue);

});

$timeout(function(){

        $scope.name = "world";

},1000);
監測多個屬性

貼出一個具體的demo

複製程式碼
<body ng-app="app" ng-controller="first">
        <button ng-click="name='a'">1</button>
        <button ng-click="name='b'">2</button>
        <button ng-click="name='c'">3</button>
        <button ng-click="type=2">4</button>
        <button ng-click="type=3">5</button>
        <p>{{name}}</p>
    </body>
    <script type="text/javascript">
        var app = angular.module("app", []);
        app.controller("first", function($scope) {
            $scope.name = 'q';
            $scope.type = 1;

            function te() {
                console.log($scope.name+" "+ $scope.type);
            }
            $scope.$watch('name+type', function(newValue, oldValue) {
                te();
            });
        })
    </script>

 

 

$watch效能問題

太多的$watch將會導致效能問題,$watch如果不再使用,我們最好將其釋放掉。

$watch函式返回一個登出監聽的函式,如果我們想監控一個屬性,然後在稍後登出它,可以使用下面的方式:

var watch = $scope.$watch('someModel.someProperty', callback);

//...

watch();

 

還有2個和$watch相關的函式:

$watchGroup(watchExpressions, listener);

$watchCollection(obj, listener);