中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

做算法題的 網(wǎng)站成品網(wǎng)站貨源1

做算法題的 網(wǎng)站,成品網(wǎng)站貨源1,簡單靜態(tài)網(wǎng)頁制作,揚(yáng)州網(wǎng)站建設(shè)icp備微服務(wù)-MybatisPlus下 文章目錄 微服務(wù)-MybatisPlus下1 MybatisPlus擴(kuò)展功能1.1 代碼生成1.2 靜態(tài)工具1.3 邏輯刪除1.4 枚舉處理器1.5 JSON處理器**1.5.1.定義實(shí)體****1.5.2.使用類型處理器** **1.6 配置加密(選學(xué))**1.6.1.生成秘鑰**1.6.2.修改配置****…

微服務(wù)-MybatisPlus下

文章目錄

  • 微服務(wù)-MybatisPlus下
    • 1 MybatisPlus擴(kuò)展功能
      • 1.1 代碼生成
      • 1.2 靜態(tài)工具
      • 1.3 邏輯刪除
      • 1.4 枚舉處理器
      • 1.5 JSON處理器
        • **1.5.1.定義實(shí)體**
        • **1.5.2.使用類型處理器**
      • **1.6 配置加密(選學(xué))**
        • 1.6.1.生成秘鑰
        • **1.6.2.修改配置**
        • **1.6.3.測(cè)試**
    • 2 插件功能
      • 2.1 分頁插件
      • 2.2 通用分頁實(shí)體
        • 2.2.1 簡單分頁查詢
        • 2.2.2 通用分頁查詢

1 MybatisPlus擴(kuò)展功能

1.1 代碼生成

自己從頭開始,則步驟如下圖所示


在這里插入圖片描述

在這里插入圖片描述

1.2 靜態(tài)工具

有的時(shí)候Service之間也會(huì)相互調(diào)用,為了避免出現(xiàn)循環(huán)依賴問題,MybatisPlus提供一個(gè)靜態(tài)工具類:Db,其中的一些靜態(tài)方法IService中方法 簽名基本一致。主要差別就是由于是靜態(tài)的,之前沒有指定過實(shí)體對(duì)象,所以除save、update以外的函數(shù)幾乎都要傳入實(shí)體類,讓底層調(diào)用反射機(jī)制,得到實(shí)體類。而save、update由于本身參數(shù)就需要傳入一個(gè)實(shí)體類對(duì)象,此對(duì)象就可通過反射得到實(shí)體類,所以不需要再傳入實(shí)體類。

實(shí)現(xiàn)CRUD功能:

案例:靜態(tài)工具查詢

需求:

  1. 改造根據(jù)id查詢用戶的接口,查詢用戶的同時(shí),查詢出用戶對(duì)應(yīng)的所有地址
  2. 改造根據(jù)id批量查詢用戶的接口,查詢用戶的同時(shí),查詢出用戶對(duì)應(yīng)的所有地址
  3. 實(shí)現(xiàn)根據(jù)用戶id查詢收貨地址功能,需要驗(yàn)證用戶狀態(tài),凍結(jié)用戶拋出異常(練習(xí))

可以看到以上需求一般都需要在注入了userService之后,再注入addressService才能實(shí)現(xiàn)(當(dāng)然你用多表聯(lián)合或者注入mapper當(dāng)我沒說)。那這就涉及到了多個(gè)Service的相互調(diào)用,出現(xiàn)循環(huán)依賴問題,這種情況下就可以使用靜態(tài)工具來解決。而且靜態(tài)工具不需要注入,這樣就避免了循環(huán)依賴

第一題:

  • controller層
    @GetMapping("{id}")@ApiOperation(value = "根據(jù)id查詢用戶接口")public UserVO queryUserById(@ApiParam("用戶id") @PathVariable("id") Long id){
//        User user = userService.getById(id);
//        UserVO userVO = BeanUtil.copyProperties(user, UserVO.class);
//        return userVO;return userService.queryUserAndAddressById(id);}
  • service層
    @Overridepublic UserVO queryUserAndAddressById(Long id) {//1. 查詢用戶User user = getById(id);if(user == null || user.getStatus() == 2){throw new RuntimeException("用戶狀態(tài)異常");}//2. 查詢地址//這里本來可以直接用本service的lambdaQuery函數(shù) 單位了避免循環(huán)依賴,就使用靜態(tài)工具List<Address> list = Db.lambdaQuery(Address.class).eq(Address::getUserId, user.getId()).list();//3. 封裝vo//3.1 轉(zhuǎn)User的PO為VoUserVO userVO = BeanUtil.copyProperties(user, UserVO.class);//3.2 轉(zhuǎn)地址VOif(CollUtil.isNotEmpty(list)){userVO.setAddressList(BeanUtil.copyToList(list, AddressVO.class));}return userVO;}

第二題:

    @Overridepublic List<UserVO> queryUserAndAddressByIds(List<Long> ids) {//1. 查詢用戶List<User> users = listByIds(ids);if(CollUtil.isEmpty(users)){return Collections.emptyList();}//2. 查詢地址//2.1 獲取用戶id集合List<Long> userIds = users.stream().map(User::getId).collect(Collectors.toList());//2.2 根據(jù)用戶id查詢地址List<Address> addresses = Db.lambdaQuery(Address.class).in(Address::getUserId, userIds).list();//2.3 轉(zhuǎn)換地址VOList<AddressVO> addressVOList = BeanUtil.copyToList(addresses, AddressVO.class);//2.4 用戶地址集合分組處理、相同用戶的放入一個(gè)集合(組)中Map<Long, List<AddressVO>> addressMap = new HashMap<>(0);if(CollUtil.isNotEmpty(addressVOList)) {addressMap = addressVOList.stream().collect(Collectors.groupingBy(AddressVO::getUserId));}//3. 轉(zhuǎn)換為VO返回List<UserVO> list = new ArrayList<>(users.size());for(User user:users){//3.1 轉(zhuǎn)換user的PO為VOUserVO userVO = BeanUtil.copyProperties(user, UserVO.class);list.add(userVO);//3.2 轉(zhuǎn)換為VOuserVO.setAddressList(addressMap.get(user.getId()));}return list;}

也就是靜態(tài)工具的使用和IService一樣,只不過多了個(gè)實(shí)體類傳入。當(dāng)一個(gè)serivice中需要多個(gè)service時(shí),就是用靜態(tài)工具,用法類似,也有普通函數(shù)以及復(fù)雜條件查詢函數(shù),比如Db.lambdaQuery,Db.Db.lambdaUpdate。

1.3 邏輯刪除

邏輯刪除就是基于代碼邏輯模擬刪除效果,但并不會(huì)真正刪除數(shù)據(jù)。思路如下:

  • 在表中添加一個(gè)字段標(biāo)記數(shù)據(jù)是否被刪除
  • 當(dāng)刪除數(shù)據(jù)時(shí)把標(biāo)記置為1
  • 查詢時(shí)只查詢標(biāo)記為0的數(shù)據(jù)

在這里插入圖片描述

MybatisPlus提供了邏輯刪除技能,無需改變方法調(diào)用的方法,而是在底層幫我們自動(dòng)修改CRUD的語句。我們要做的就是在applicaiton.yaml文件中配置邏輯刪除的字段名稱和值即可。

在這里插入圖片描述

    @Autowiredprotected AddressService addressService;@Testvoid testLogicDelete(){//1. 刪除addressService.removeById(59L);//2. 查詢Address address = addressService.getById(59L);System.out.println("address = " + address);}

雖然使用的remove方法,但是實(shí)際執(zhí)行的是update方法。且在數(shù)據(jù)庫中還存在,只不過deleted變成了true

在這里插入圖片描述

1.4 枚舉處理器

User類中有一個(gè)用戶狀態(tài)字段:

在這里插入圖片描述

使用枚舉表示狀態(tài),可以提高可讀性。但是問題來了

在這里插入圖片描述

數(shù)據(jù)庫中status仍然是int類型,這就需要一個(gè)枚舉類型到int類型的轉(zhuǎn)化。

在這里插入圖片描述

幸運(yùn)的是Mybatis和mp幫我們解決了,如上圖所示。只需要在枚舉類中對(duì)應(yīng)的字段上加上@EnumValue注釋 mp就會(huì)自動(dòng)把對(duì)應(yīng)的字段值與數(shù)據(jù)庫中列匹配

在這里插入圖片描述

在applicaiton.yml中配置全局枚舉類處理器

在這里插入圖片描述

@JsonValue //用于枚舉的返回值 數(shù)據(jù)庫返回顯示的值,比如此處是返回desc的值 也可以返回value的值 否則默認(rèn)返回的是枚舉的對(duì)象名 比如此處的NORMAL FROZEN

@Getter
public enum UserStatus {NORMAL(1,"正常"),FROZEN(2,"凍結(jié)"),;@EnumValueprivate final int value;@JsonValue  //用于枚舉的返回值 數(shù)據(jù)庫返回顯示的值private final String desc;UserStatus(int value,String desc){this.value = value;this.desc = desc;}}

在這里插入圖片描述

1.5 JSON處理器

數(shù)據(jù)庫的user表中有一個(gè)info字段,是JSON類型:

在這里插入圖片描述

格式像這樣:

{"age": 20, "intro": "佛系青年", "gender": "male"}

而目前User實(shí)體類中卻是String類型:

在這里插入圖片描述

這樣一來,我們要讀取info中的屬性時(shí)就非常不方便。如果要方便獲取,info的類型最好是一個(gè)Map或者實(shí)體類。

而一旦我們把info改為對(duì)象類型,就需要在寫入數(shù)據(jù)庫時(shí)手動(dòng)轉(zhuǎn)為String,再讀取數(shù)據(jù)庫時(shí),手動(dòng)轉(zhuǎn)換為對(duì)象,這會(huì)非常麻煩。

意思就是對(duì)象的String字段可以被mp自動(dòng)轉(zhuǎn)換為數(shù)據(jù)庫中的JSON,但是數(shù)據(jù)庫中的JSON不能被mp自動(dòng)幫我們轉(zhuǎn)換為String或者相應(yīng)的對(duì)象

因此MybatisPlus提供了很多特殊類型字段的類型處理器,解決特殊字段類型與數(shù)據(jù)庫類型轉(zhuǎn)換的問題。例如處理JSON就可以使用JacksonTypeHandler處理器。

在這里插入圖片描述

1.5.1.定義實(shí)體

首先,我們定義一個(gè)單獨(dú)實(shí)體類來與info字段的屬性匹配:

在這里插入圖片描述

代碼如下:

package com.itheima.mp.domain.po;import lombok.Data;@Data
public class UserInfo {private Integer age;private String intro;private String gender;
}
1.5.2.使用類型處理器

接下來,將User類的info字段修改為UserInfo類型,并聲明類型處理器:

在這里插入圖片描述

測(cè)試可以發(fā)現(xiàn),所有數(shù)據(jù)都正確封裝到UserInfo當(dāng)中了:

在這里插入圖片描述

同時(shí),為了讓頁面返回的結(jié)果也以對(duì)象格式返回,我們要修改UserVO中的info字段:

在這里插入圖片描述

此時(shí),在頁面查詢結(jié)果如下:

在這里插入圖片描述

注意: 由于User類中嵌套了UserInfo類,出現(xiàn)了類的嵌套,那么就需要定義復(fù)雜的ResultMap,但是我們又不想定義,那么就直接在User類上加注釋,autoResultMap = true 如下圖所示

在這里插入圖片描述

1.6 配置加密(選學(xué))

目前我們配置文件中的很多參數(shù)都是明文,如果開發(fā)人員發(fā)生流動(dòng),很容易導(dǎo)致敏感信息的泄露。所以MybatisPlus支持配置文件的加密和解密功能。

我們以數(shù)據(jù)庫的用戶名和密碼為例。

1.6.1.生成秘鑰

首先,我們利用AES工具生成一個(gè)隨機(jī)秘鑰,然后對(duì)用戶名、密碼加密:

package com.itheima.mp;import com.baomidou.mybatisplus.core.toolkit.AES;
import org.junit.jupiter.api.Test;class MpDemoApplicationTests {@Testvoid contextLoads() {// 生成 16 位隨機(jī) AES 密鑰String randomKey = AES.generateRandomKey();System.out.println("randomKey = " + randomKey);// 利用密鑰對(duì)用戶名加密String username = AES.encrypt("root", randomKey);System.out.println("username = " + username);// 利用密鑰對(duì)用戶名加密String password = AES.encrypt("MySQL123", randomKey);System.out.println("password = " + password);}
}

打印結(jié)果如下:

randomKey = 6234633a66fb399f
username = px2bAbnUfiY8K/IgsKvscg==
password = FGvCSEaOuga3ulDAsxw68Q==
1.6.2.修改配置

修改application.yaml文件,把jdbc的用戶名、密碼修改為剛剛加密生成的密文:

spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mp?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=truedriver-class-name: com.mysql.cj.jdbc.Driverusername: mpw:QWWVnk1Oal3258x5rVhaeQ== # 密文要以 mpw:開頭password: mpw:EUFmeH3cNAzdRGdOQcabWg== # 密文要以 mpw:開頭
1.6.3.測(cè)試

在啟動(dòng)項(xiàng)目的時(shí)候,需要把剛才生成的秘鑰添加到啟動(dòng)參數(shù)中,像這樣:

–mpw.key=6234633a66fb399f

單元測(cè)試的時(shí)候不能添加啟動(dòng)參數(shù),所以要在測(cè)試類的注解上配置:

在這里插入圖片描述

然后隨意運(yùn)行一個(gè)單元測(cè)試,可以發(fā)現(xiàn)數(shù)據(jù)庫查詢正常。

2 插件功能

MyBatisPlus提供的內(nèi)置攔截器有下面這些

2.1 分頁插件

在未引入分頁插件的情況下,MybatisPlus是不支持分頁功能的,IServiceBaseMapper中的分頁方法都無法正常起效。 所以,我們必須配置分頁插件。

  • 首先,要在配置類中注冊(cè)MyBatisPlus的核心插件,同時(shí)添加分頁插件

  • 接著,就可以使用分頁的API了

在這里插入圖片描述

在這里插入圖片描述

    void testPageQuery(){int pageNo = 1;int pageSize = 2;//1. 準(zhǔn)備分頁條件//1.1 分頁條件Page<User> page = Page.of(pageNo, pageSize);//1.2 排序條件  可以指定多個(gè) 比如下面 余額相同則按id排序page.addOrder(new OrderItem("balance",true));page.addOrder(new OrderItem("id",true));//2. 分頁查詢Page<User> p = userService.page(page);//3. 解析long total = p.getTotal();  //總條數(shù)System.out.println("total = " + total);long pages = p.getPages();  //總頁數(shù)System.out.println("pages = " + pages);List<User> records = p.getRecords();    //分頁數(shù)據(jù)records.forEach(System.out::println);}

2.2 通用分頁實(shí)體

2.2.1 簡單分頁查詢

案例:簡單分頁查詢案例

需求:遵循下面的接口規(guī)范,編寫一個(gè)UserController接口,實(shí)現(xiàn)User的分頁查詢

在這里插入圖片描述

  • 實(shí)體類
public class PageQuery {@ApiModelProperty("頁碼")private Integer pageNo;@ApiModelProperty("頁大小")private Integer pageSize;@ApiModelProperty("排序字段")private String sortBy;@ApiModelProperty("是否升序")private Boolean isAsc;
}@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel(description = "用戶查詢條件實(shí)體")
public class UserQuery extends PageQuery{@ApiModelProperty("用戶名關(guān)鍵字")private String name;@ApiModelProperty("用戶狀態(tài):1-正常,2-凍結(jié)")private Integer status;@ApiModelProperty("余額最小值")private Integer minBalance;@ApiModelProperty("余額最大值")private Integer maxBalance;
}
  • controller
    @GetMapping("/page")@ApiOperation(value = "根據(jù)條件分頁查詢用戶接口")public PageDTO<UserVO> queryUsersPage(UserQuery query){return userService.queryUsersPage(query);}
  • impl層
    @Overridepublic PageDTO<UserVO> queryUsersPage(UserQuery query) {String name = query.getName();Integer status = query.getStatus();//1. 構(gòu)建查詢條件Page<User> page = Page.of(query.getPageNo(), query.getPageSize());if(StrUtil.isNotBlank(query.getSortBy())){//不為空page.addOrder(new OrderItem(query.getSortBy(),query.getIsAsc()));}else {//為空 默認(rèn)按照更新時(shí)間排序page.addOrder(new OrderItem("update_time",false));}//2. 分頁查詢Page<User> p = lambdaQuery().like(name != null, User::getUsername, name).eq(status != null, User::getStatus, status)
//                .ge(minBalance != null, User::getBalance, minBalance)
//                .le(maxBalance != null, User::getBalance, maxBalance).page(page);//3. 封裝VO結(jié)果PageDTO<UserVO> userVOPageDTO = new PageDTO<>();userVOPageDTO.setTotal(p.getTotal());userVOPageDTO.setPages(p.getPages());List<User> records = p.getRecords();if(CollUtil.isEmpty(records)){userVOPageDTO.setList(Collections.emptyList());}else {List<UserVO> userVOS = BeanUtil.copyToList(records, UserVO.class);userVOPageDTO.setList(userVOS);}//4. 返回return userVOPageDTO;}
2.2.2 通用分頁查詢

在這里插入圖片描述

  • 改造PageQuery類
@Data
@ApiModel(description = "分頁查詢實(shí)體")
public class PageQuery {@ApiModelProperty("頁碼")private Integer pageNo = 1;@ApiModelProperty("頁大小")private Integer pageSize = 5;@ApiModelProperty("排序字段")private String sortBy;@ApiModelProperty("是否升序")private Boolean isAsc = true;public <T>  Page<T> toMpPage(OrderItem ... orders){// 1.分頁條件Page<T> p = Page.of(pageNo, pageSize);// 2.排序條件// 2.1.先看前端有沒有傳排序字段if (sortBy != null) {p.addOrder(new OrderItem(sortBy, isAsc));return p;}// 2.2.再看有沒有手動(dòng)指定排序字段if(orders != null){p.addOrder(orders);}return p;}public <T> Page<T> toMpPage(String defaultSortBy, boolean isAsc){return this.toMpPage(new OrderItem(defaultSortBy, isAsc));}public <T> Page<T> toMpPageDefaultSortByCreateTimeDesc() {return toMpPage("create_time", false);}public <T> Page<T> toMpPageDefaultSortByUpdateTimeDesc() {return toMpPage("update_time", false);}
}
  • 改造PageDTO類
@Data
@ApiModel(description = "分頁結(jié)果")
@AllArgsConstructor
@NoArgsConstructor
public class PageDTO<T> {@ApiModelProperty("總條數(shù)")private Long total;@ApiModelProperty("總頁數(shù)")private Long pages;@ApiModelProperty("總數(shù)據(jù)")private List<T> list;/*** 返回空分頁結(jié)果* @param p MybatisPlus的分頁結(jié)果* @param <V> 目標(biāo)VO類型* @param <P> 原始PO類型* @return VO的分頁對(duì)象*/public static <V, P> PageDTO<V> empty(Page<P> p){return new PageDTO<>(p.getTotal(), p.getPages(), Collections.emptyList());}/*** 將MybatisPlus分頁結(jié)果轉(zhuǎn)為 VO分頁結(jié)果* @param p MybatisPlus的分頁結(jié)果* @param voClass 目標(biāo)VO類型的字節(jié)碼* @param <V> 目標(biāo)VO類型* @param <P> 原始PO類型* @return VO的分頁對(duì)象*/public static <V, P> PageDTO<V> of(Page<P> p, Class<V> voClass) {// 1.非空校驗(yàn)List<P> records = p.getRecords();if (records == null || records.size() <= 0) {// 無數(shù)據(jù),返回空結(jié)果return empty(p);}// 2.數(shù)據(jù)轉(zhuǎn)換List<V> vos = BeanUtil.copyToList(records, voClass);// 3.封裝返回return new PageDTO<>(p.getTotal(), p.getPages(), vos);}/*** 將MybatisPlus分頁結(jié)果轉(zhuǎn)為 VO分頁結(jié)果,允許用戶自定義PO到VO的轉(zhuǎn)換方式* @param p MybatisPlus的分頁結(jié)果* @param convertor PO到VO的轉(zhuǎn)換函數(shù)* @param <V> 目標(biāo)VO類型* @param <P> 原始PO類型* @return VO的分頁對(duì)象*/public static <V, P> PageDTO<V> of(Page<P> p, Function<P, V> convertor) {// 1.非空校驗(yàn)List<P> records = p.getRecords();if (records == null || records.size() <= 0) {// 無數(shù)據(jù),返回空結(jié)果return empty(p);}// 2.數(shù)據(jù)轉(zhuǎn)換List<V> vos = records.stream().map(convertor).collect(Collectors.toList());// 3.封裝返回return new PageDTO<>(p.getTotal(), p.getPages(), vos);}}
  • impl層
    @Overridepublic PageDTO<UserVO> queryUsersPage(UserQuery query) {String name = query.getName();Integer status = query.getStatus();//1. 構(gòu)建查詢條件Page<User> page = query.toMpPageDefaultSortByUpdateTimeDesc();Page<User> p = lambdaQuery().like(name != null, User::getUsername, name).eq(status != null, User::getStatus, status).page(page);return PageDTO.of(page, UserVO.class);}
http://www.risenshineclean.com/news/1217.html

相關(guān)文章:

  • 網(wǎng)站建設(shè)策劃實(shí)訓(xùn)總結(jié)友情鏈接怎么連
  • 遵義新藍(lán)外國語學(xué)校網(wǎng)站建設(shè)臺(tái)州seo優(yōu)化
  • 郴州北湖區(qū)疫情最新消息網(wǎng)站優(yōu)化
  • 建設(shè)企業(yè)網(wǎng)站進(jìn)去無法顯示怎么在百度上免費(fèi)做廣告
  • 如何通過做網(wǎng)站月入上萬廣州seo公司品牌
  • 溫州建設(shè)網(wǎng)站百度上??偛?/a>
  • 天津企商網(wǎng)站建設(shè)公司關(guān)鍵詞優(yōu)化按天計(jì)費(fèi)
  • 網(wǎng)站如何做銀聯(lián)在線支付大連中小企業(yè)網(wǎng)絡(luò)營銷
  • 一般做外貿(mào)上什么網(wǎng)站熱狗網(wǎng)站排名優(yōu)化外包
  • 建設(shè)網(wǎng)站com艾滋病阻斷藥
  • 網(wǎng)站robots.txt檢測(cè)網(wǎng)站關(guān)鍵詞在線優(yōu)化
  • 用html5做的個(gè)人網(wǎng)站網(wǎng)絡(luò)營銷試卷及答案
  • python合適做網(wǎng)站嗎海外網(wǎng)絡(luò)推廣方案
  • 做網(wǎng)站圖片百度競價(jià)排名系統(tǒng)
  • 網(wǎng)站 默認(rèn)首頁濟(jì)南seo的排名優(yōu)化
  • 商城開發(fā)價(jià)格服務(wù)排名優(yōu)化百度
  • 和先鋒影音和做的網(wǎng)站百度關(guān)鍵詞排名推廣
  • 騎行網(wǎng)站模板網(wǎng)站搭建平臺(tái)
  • wordpress 黃藍(lán) 現(xiàn)代企業(yè)教程seo推廣排名網(wǎng)站
  • 建立網(wǎng)站需要注冊(cè)公司嗎seo引擎優(yōu)化公司
  • 網(wǎng)站做哪些主題比較容易做幽默廣告軟文案例
  • 專做外貿(mào)衣服鞋網(wǎng)站有哪些網(wǎng)址搜索引擎入口
  • 還有什么網(wǎng)站可以做面包車?yán)涀鲆粋€(gè)網(wǎng)站需要多少錢大概
  • 福建網(wǎng)站建設(shè)公司交換友情鏈接的意義是什么
  • 常州建設(shè)工程監(jiān)理員掛證網(wǎng)站百度軟件開放平臺(tái)
  • 做網(wǎng)站的時(shí)候賣過假貨而出過事搜索引擎優(yōu)化是免費(fèi)的嗎
  • 重點(diǎn)項(xiàng)目建設(shè)網(wǎng)站商業(yè)策劃公司十大公司
  • 營銷型網(wǎng)站系統(tǒng)網(wǎng)絡(luò)營銷策劃方案
  • 國內(nèi)做新聞比較好的網(wǎng)站有哪些企業(yè)網(wǎng)站制作公司
  • wordpress漢語公益搜索網(wǎng)站排名優(yōu)化