利用MyBatis的動態SQL特性抽象統一SQL查詢接口

1. SQL查詢的統一抽象

?MyBatis制動動態SQL的構造,利用動態SQL和自定義的參數Bean抽象,可以將絕大部分SQL查詢抽象為一個統一接口,查詢參數使用一個自定義bean繼承Map,使用映射的方法構造多查詢參數.在遇到多屬性參數(例如order by,其參數包括列名,升序降序類型,以及可以多個列及升降序類型憑借在order by之后)無法使用簡單的key-value表示時,可以將參數單獨抽象為一個類.

將要用到的bean

package com.xxx.mybatistask.bean;import com.xxx.mybatistask.support.jsonSerializer.JsonDateDeserializer;
import com.xxx.mybatistask.support.jsonSerializer.JsonDateSerializer;
import org.codehaus.jackson.map.annotate.JsonDeserialize;
import org.codehaus.jackson.map.annotate.JsonSerialize;import java.util.Date;public class Post {private int id;private String title;private String content;private String author;private PostStatus status;private Date created;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public String getAuthor() {return author;}public void setAuthor(String author) {this.author = author;}public PostStatus getStatus() {return status;}public void setStatus(PostStatus status) {this.status = status;}@JsonSerialize(using = JsonDateSerializer.class)public Date getCreated() {return created;}@JsonDeserialize(using = JsonDateDeserializer.class)public void setCreated(Date created) {this.created = created;}
}

?

?

1)參數Bean設計

總的參數Map抽象接口設計

package com.xxx.mybatistask.bean.query;import java.util.Map;public interface QueryParam extends Map<String, Object> {/*** 新增查詢參數** @param key   參數名* @param value 參數值* @return*/QueryParam fill(String key, Object value);
}

?

列表查詢參數接口

package com.xxx.mybatistask.bean.query;import java.util.List;public interface ListQueryParam extends QueryParam {/*** 獲取排序條件集合** @return*/List<SortCond> getSortCond();/*** 添加排序條件** @param sortCond*/void addSortCond(SortCond sortCond);void addSortCond(List<SortCond> sortCondList);/*** 獲取當前頁數** @return*/Integer getPage();/*** 獲取每頁查詢記錄數** @return*/Integer getPageSize();/*** 設置當前頁數*/void setPage(Integer page);/*** 設置每頁查詢記錄數*/void setPageSize(Integer pageSize);
}

?

列表查詢參數接口實現

package com.xxx.mybatistask.bean.query;import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;public class GenericQueryParam extends LinkedHashMap<String, Object> implements ListQueryParam {/*** 最大單頁記錄數*/public final static int MAX_PAGE_SIZE = 100;/*** 當前頁面key*/private final static String PAGE_KEY = "__page";/*** 單頁記錄數key*/private final static String PAGESIZE_KEY = "__pagesize";/*** 排序參數List key*/private final static String SORTCOND_KEY = "__sortcond";public GenericQueryParam() {this(1, 10);}public GenericQueryParam(Integer page,Integer pageSize) {setPage(page);setPageSize(pageSize);}@Overridepublic Integer getPage() {return (Integer) get(PAGE_KEY);}@Overridepublic Integer getPageSize() {return (Integer) get(PAGESIZE_KEY);}@Overridepublic void setPage(Integer page) {put(PAGE_KEY, page);}@Overridepublic void setPageSize(Integer pageSize) {put(PAGESIZE_KEY, pageSize);}@Override@SuppressWarnings("unchecked")public List<SortCond> getSortCond() {List<SortCond> sortCondList = (List<SortCond>) get(SORTCOND_KEY);if (sortCondList == null) {sortCondList = new LinkedList<SortCond>();put(SORTCOND_KEY, sortCondList);}return sortCondList;}@Override@SuppressWarnings("unchecked")public void addSortCond(SortCond sortCond) {List<SortCond> sortCondList = (List<SortCond>) get(SORTCOND_KEY);if (sortCondList == null) {sortCondList = new LinkedList<SortCond>();put(SORTCOND_KEY, sortCondList);}sortCondList.add(sortCond);}@Overridepublic void addSortCond(List<SortCond> sortCondList) {for (SortCond sortCond : sortCondList) addSortCond(sortCond);}@Overridepublic QueryParam fill(String key, Object value) {put(key, value);return this;}
}

?

?

排序參數的抽象

package com.xxx.mybatistask.bean.query;public class SortCond {/*** 排序類型枚舉*/public enum Order {ASC, DESC}/*** 排序類型*/private String column;/*** 排序類型*/private Order order;public SortCond(String column) {this(column, Order.DESC);}public SortCond(String column, Order order) {this.column = column;this.order = order;}public String getColumn() {return column;}public Order getOrder() {return order;}
}

?

?

2)Service查詢接口設計

package com.xxx.mybatistask.service;import com.xxx.mybatistask.bean.query.GenericQueryParam;
import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.annotation.Resource;public abstract class AbstractService {protected final Logger logger = LoggerFactory.getLogger(getClass());@Resourceprotected SqlSession sqlSession;/*** 分頁參數校驗** @param params* @param rowCount* @return*/protected void pageParamValidate(GenericQueryParam params, int rowCount) {int page = params.getPage();int pageSize = params.getPageSize();if (page < 1) page = 1;if (pageSize < 1) pageSize = 1;if (pageSize > GenericQueryParam.MAX_PAGE_SIZE)pageSize = GenericQueryParam.MAX_PAGE_SIZE;int maxPage = (int) Math.ceil((double) rowCount / pageSize);if (page > maxPage) page = maxPage;params.setPage(page);params.setPageSize(pageSize);}
}

?

?

package com.xxx.mybatistask.service;import com.xxx.mybatistask.bean.Post;
import com.xxx.mybatistask.bean.query.GenericQueryParam;
import com.xxx.mybatistask.bean.query.ListResult;public interface PostService {/*** 查詢參數列名枚舉*/public enum PostQueryPram {title, content, author, status, created}void create(Post post);/*** 翻頁查詢** @param param* @return*/ListResult<Post> select(GenericQueryParam param);void update(Post post);
}

?

?

package com.xxx.mybatistask.service.impl;import com.xxx.mybatistask.bean.Post;
import com.xxx.mybatistask.bean.query.GenericQueryParam;
import com.xxx.mybatistask.bean.query.ListResult;
import com.xxx.mybatistask.service.AbstractService;
import com.xxx.mybatistask.service.PostService;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Service;import java.util.LinkedList;
import java.util.List;@Service
public class PostServiceImpl extends AbstractService implements PostService {@Overridepublic void create(Post post) {sqlSession.insert("post.insert", post);}@Overridepublic ListResult<Post> select(GenericQueryParam params) {Integer rowCount = sqlSession.selectOne("post.selectCount", params);if (rowCount == 0) {return new ListResult<Post>(new LinkedList<Post>(), 0);}// 分頁參數檢查
        pageParamValidate(params, rowCount);int page = params.getPage();int pageSize = params.getPageSize();int offset = (page - 1) * pageSize;RowBounds rowBounds = new RowBounds(offset, pageSize);List<Post> postList = sqlSession.selectList("post.select", params, rowBounds);return new ListResult<Post>(postList, rowCount);}@Overridepublic void update(Post post) {sqlSession.update("post.update", post);}
}

?

?

?

3)自定義參數bean的解析與轉換

以SortCond為例,由于是多屬性查詢參數,所以我們需要自己定義參數在客戶端的文本格式,從客戶端傳入后再使用自定義的Paser來將其包裝成SortCond

例如此處我們定義的排序參數在url中的格式為

/api/post/query/title/an?page=3&pageSize=200&sorts=created:DESC|author:ASC

其中排序參數為 "created:DESC|author:ASC" , 解析類如下

package com.xxx.mybatistask.support.stringparser;import java.util.List;public interface Parser<T> {/*** 字符串轉對象** @param parseString 待轉換字符串* @return List<T>  轉換完成的對象List*/List<T> parseList(String parseString);
}

?

package com.xxx.mybatistask.support.stringparser;import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.xxx.mybatistask.bean.query.SortCond;import java.util.List;
import java.util.Map;public class SortCondParser implements Parser<SortCond> {/*** 排序列分隔符*/private static final String COL_SPLITTER = "|";/*** 順序類型分隔符*/private static final String ORDER_SPLITTER = ":";/*** 列名檢查*/private Class<? extends Enum> columnEnumCls;public SortCondParser(Class<? extends Enum> columnEnumCls) {this.columnEnumCls = columnEnumCls;}/*** 將字符串轉換為SortCond* 字符串的標準格式為* title:ASC|created:DESC** @param parseString 待轉換字符串* @return*/@Overridepublic List<SortCond> parseList(String parseString) {List<SortCond> sortCondList = Lists.newArrayList();// 將字符串切分為 {"column" => "order"} 的形式Map<String, String> sortOrderMap =Splitter.on(COL_SPLITTER).trimResults().omitEmptyStrings().withKeyValueSeparator(ORDER_SPLITTER).split(parseString);String column = null;String order = null;for (Map.Entry<String, String> entry : sortOrderMap.entrySet()) {// 驗證column合法性column = entry.getKey();if (column != null && !column.equals("")) {Enum.valueOf(columnEnumCls, column);} else {break;}// 驗證order合法性order = entry.getValue();if (order != null && !order.equals("")) {Enum.valueOf(SortCond.Order.class, order);} else {order = SortCond.Order.DESC.name();}sortCondList.add(new SortCond(column, SortCond.Order.valueOf(order)));}return sortCondList;}
}

?

?

4) 動態查詢SQL的編寫

<select id="select"parameterType="com.xxx.mybatistask.bean.query.GenericQueryParam"resultType="com.xxx.mybatistask.bean.Post"><![CDATA[selectid,title,content,author,status,createdfrompost]]><where><if test="id != null">and id = #{id}</if><if test="title != null and title != ''">and title like concat('%', #{title}, '%')</if><if test="author != null and author != ''">and author like concat('%', #{author}, '%')</if><if test="content != null and content != ''">and match(content) against(#{content})</if><if test="status != null">and status = #{status}</if><if test="created != null and created != ''">and created = #{created}</if></where><if test="_parameter.getSortCond().size() != 0">order by<foreach collection="_parameter.getSortCond()" item="sortCond" separator=",">${sortCond.column} ${sortCond.order}</foreach></if></select>

?

至此SQL抽象接口以及完成,結合SortCond類,動態SQL和OGNL動態生成了order by參數,而類似的像 JOIN ... ON (USING) 或者 GROUP BY ... HAVING 等查詢參數條件,也可以將其抽象成bean,通過GenericQueryParam成員變量的形式拼接到SQL查詢語句中來

另外代碼中并沒有對參數進行過多的檢查,原因是:

1. MyBatis SQL查詢使用prepareStatement,對于注入問題相對安全

2. 動態SQL查詢使用<if>判斷where查詢條件,如果參數中的map key不是有效列名,將不會拼接到SQL語句中

3. 即使由于惡意用戶篡改參數格式造成不規范參數的SQL查詢異常,對于這種異常只需要重定向到全局error頁面即可

?

5) Controller調用示例

@RequestMapping(value = "/query/{colKey}/{colVal}", method = RequestMethod.GET)public@ResponseBodyObject query(@PathVariable String colKey,@PathVariable String colVal,@RequestParam(value = "status", required = false) String status,@RequestParam(value = "page", required = false, defaultValue = "1") Integer page,@RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize,@RequestParam(value = "sorts", required = false, defaultValue = "") String sorts) {// page and colGenericQueryParam params = new GenericQueryParam(page, pageSize);params.fill(colKey, colVal).fill(PostService.PostQueryPram.status.name(),PostStatus.valueOf(status));// sortsSortCondParser sortCondParser = new SortCondParser(PostService.PostQueryPram.class);params.addSortCond(sortCondParser.parseList(sorts));ListResult<Post> postList = postService.select(params);return dataJson(postList);}

?

?

?

?

2. TypeHandler設計

上文中的bean Post類中status屬性類型是enum類,如下

package com.xxx.mybatistask.bean;public enum PostStatus {NORMAL(0, "正常"), LOCKED(1, "鎖定");private int code;private String text;private PostStatus(int code, String text) {this.code = code;this.text = text;}public int code() {return code;}public String text() {return text;}public static PostStatus codeOf(int code) {for (PostStatus postStatus : PostStatus.values()) {if (postStatus.code == code) {return postStatus;}}throw new IllegalArgumentException("invalid code");}public static boolean contains(String text) {for (PostStatus postStatus : PostStatus.values()) {if (postStatus.toString().equals(text)) {return true;}}return false;}
}

?

而這個屬性在數據庫中的類型實際上市一個tinyint表示的標記位,為了讓mybatis jdbc自動轉換這個tinyint標記位為enum(查詢時)和轉換enum為tinyint(插入更新時),需要編寫mybatis typehandler

package com.xxx.mybatistask.support.typehandler;import com.xxx.mybatistask.bean.PostStatus;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class PostStatusTypeHandler implements TypeHandler<PostStatus> {/*** PostStatus插入數據庫時轉換的方法* 將使用PostStatus的code插入數據庫** @param preparedStatement* @param index* @param postStatus* @param jdbcType* @throws SQLException*/@Overridepublic void setParameter(PreparedStatement preparedStatement, int index, PostStatus postStatus, JdbcType jdbcType) throws SQLException {preparedStatement.setInt(index, postStatus.code());}/*** status查詢出來時轉為PostStatus的方法** @param resultSet* @param colName* @return* @throws SQLException*/@Overridepublic PostStatus getResult(ResultSet resultSet, String colName) throws SQLException {return PostStatus.codeOf(resultSet.getInt(colName));}@Overridepublic PostStatus getResult(ResultSet resultSet, int colIndex) throws SQLException {return PostStatus.codeOf(resultSet.getInt(colIndex));}@Overridepublic PostStatus getResult(CallableStatement callableStatement, int colIndex) throws SQLException {return PostStatus.codeOf(callableStatement.getInt(colIndex));}
}

在MyBatis配置文件中配置這個TypeHandler是其對PostStatus參數生效

    <typeHandlers><typeHandler handler="com.xxx.mybatistask.support.typehandler.PostStatusTypeHandler"javaType="com.xxx.mybatistask.bean.PostStatus"/></typeHandlers>

?

?

3. 特殊參數的序列化與反序列化

由于需要實現接收和響應JSON數據,自動將JSON數據包裝為具體對象類,此處使用了Spring的@ResponseBody以及@RequestBody標簽,JSON的轉換器為org.codehaus.jackson

但是對于某些特殊屬性,例如此處的Post里的created屬性,在bean中表現為Date類型,而在數據庫中為TIMESTAMP類型,如果直接輸出到JSON響應中,將會輸出timestamp的毫秒數,為了格式化為自定義的格式,我們需要自定義一個JSON序列化(轉為響應文本時)與反序列化(接收請求參數轉為POST類時)的類.如下

序列化類

package com.xxx.mybatistask.support.jsonSerializer;import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializerProvider;import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;public class JsonDateSerializer extends JsonSerializer<Date> {private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");@Overridepublic void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {jsonGenerator.writeString(sdf.format(date));}
}

?

反序列化類

package com.xxx.mybatistask.support.jsonSerializer;import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.ObjectCodec;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.JsonDeserializer;import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;public class JsonDateDeserializer extends JsonDeserializer<Date> {private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");@Overridepublic Date deserialize(JsonParser jsonParser,DeserializationContext deserializationContext)throws IOException {ObjectCodec oc = jsonParser.getCodec();JsonNode node = oc.readTree(jsonParser);try {return sdf.parse(node.getTextValue());} catch (ParseException e) {e.printStackTrace();}return null;}
}

?

然后注意在Post類中標明,當Jackson序列化Post類為JSON串或將JSON串反序列化成Post類時,將調用這兩個類,Post類的代碼片段

    @JsonSerialize(using = JsonDateSerializer.class)public Date getCreated() {return created;}@JsonDeserialize(using = JsonDateDeserializer.class)public void setCreated(Date created) {this.created = created;}

?

?

THE END

轉載于:https://www.cnblogs.com/zemliu/p/3248171.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/377972.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/377972.shtml
英文地址,請注明出處:http://en.pswp.cn/news/377972.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ctype函數_PHP Ctype(字符類型)函數

ctype函數Ctype功能 (Ctype functions) PHP provides some of the built-in functions, which are used to verify the characters in the string i.e. to check whether a string contains the characters of specific types. PHP提供了一些內置函數&#xff0c;這些函數用于驗…

Linux 平臺下 MySQL 5.5 安裝 說明 與 示例

一.下載說明前期的一些準備說明&#xff0c;參考&#xff1a;MySQL 發展史http://blog.csdn.net/tianlesoftware/article/details/6999245Mysql 不同版本 說明http://blog.csdn.net/tianlesoftware/article/details/6723117 MySQL 分為Community Server 和 Enterprise Edition。…

開始python之旅

接觸python緣于工作所需&#xff0c;曾經接觸過C、C等語言&#xff0c;對于編程語言在學習上大體是一個套路&#xff0c;當然套路因人而異&#xff0c;適合就好。接下來&#xff0c;我將不斷分享python的知識和學習技巧&#xff0c;共同學習。 起源 初識一門語言善于先了解語言…

LeetCode 112. 路徑總和 、113. 路徑總和 II 思考分析

目錄112. 路徑總和題目遞歸解遞歸解&#xff0c;其他人的解法迭代解&#xff0c;其他人的解法113. 路徑總和 II題目遞歸解遞歸解&#xff0c;參考別人的思路112. 路徑總和 題目 給定一個二叉樹和一個目標和&#xff0c;判斷該樹中是否存在根節點到葉子節點的路徑&#xff0c;…

kotlin 查找id_Kotlin程序查找矩陣的轉置

kotlin 查找idA transpose of a matrix is simply a flipped version of the original matrix. We can transpose a matrix by switching its rows with its columns 矩陣的轉置只是原始矩陣的翻轉形式。 我們可以通過切換矩陣的行和列來轉置矩陣 Given a matrix, we have to…

[mongodb翻譯]分片和故障轉移

一個配置恰當的mongodb 分片集群不會有單點失效。 本章節描述了集群服務器中可能出現的故障&#xff0c;及相應的對策。 1. 某個mongos路由進程故障 每一個mongos會運行每一臺應用服務器上面&#xff0c;該應用服務器只能通過這個mongos進程和集群進行通信。mongos進程不是…

看張子陽的書真是收獲很多,也醒悟了很多(一)

摘錄&#xff1a; 這是有一次開會時&#xff0c;我的老總跟我們說了這樣一個事例&#xff1a;通常來說&#xff0c;醫生是很高尚的職業&#xff08;暫不考慮國內醫生的負面新聞&#xff09;&#xff0c;尤其是牙科醫生&#xff0c; 他們有著體面的工作并且收入不菲。但是&#…

【C++ grammar】抽象、封裝與this指針

目錄1、Abstraction and Encapsulation&#xff08;抽象與封裝&#xff09;1. Data Field Encapsulation (數據域封裝)2. Accessor and Mutator (訪問器與更改器)2.1. To read/write private data, we need get/set function (為讀寫私有數據&#xff0c;需要get/set函數)2.2. …

java創建臨時文件_用Java創建一個臨時文件

java創建臨時文件The task is to create a temporary file in Java. 任務是用Java創建一個臨時文件。 Creating a temporary file 創建一個臨時文件 To create a temporary file in java – we use createTempFile() method of "File" class. The createTempFile()…

十九、圖像的形態學操作

一、圖像形態學 圖像形態學是圖像處理學科的一個單獨分支學科 主要針對的是灰度圖和二值圖像 是由數學的集合論以及數學中的拓撲幾何原理發展而來 二、膨脹操作&#xff08;dilate&#xff09; 33的卷積核 以33為卷積核從左往右(從上往下)開始運行&#xff0c;若這卷積核…

X名稱空間(WPF)

筆記簡述 閑話x名稱空間簡要x名稱空間的Attributex名稱空間的標簽擴展x名稱空間的XAML指令元素閑話 本筆記參考與《深入淺出WPF》、MSDN、Some Blog… MSDN的飛機票點這里。 x名稱空間簡要 在VS中新建個WpfApplication都會自動生成xmlns:x"http://schemas.microsoft.com/w…

基于Bresenham和DDA算法畫線段

直線&#xff1a;ykxb 為了將他在顯示屏上顯示出來&#xff0c;我們需要為相應的點賦值&#xff0c;那么考慮到計算機的乘法執行效率&#xff0c;我們肯定不會選擇用Ykxb這個表達式求值&#xff0c;然后進行畫線段。 我們應當是將它轉化為加法運算。 下面提供兩種常見的算法&am…

leetcode 106. 從中序與后序遍歷序列構造二叉樹 105. 從前序與中序遍歷序列構造二叉樹思考分析

目錄1、106題目2、參考思路&#xff1a;遞歸切割數組3、105題目4、同樣思路的代碼1、106題目 2、參考思路&#xff1a;遞歸切割數組 代碼參考&#xff1a;公眾號&#xff1a;代碼隨想錄 后序數組中序數組 以 后序數組(左右中)的最后一個元素作為切割點&#xff0c;先切中序數組…

按頻率對元素進行排序

Prerequisite: 先決條件&#xff1a; Hashing data structure 散列數據結構 How to write user-defined comparator for priority queue STL in C? 如何在C 中為優先級隊列STL編寫用戶定義的比較器&#xff1f; How to sort a map based on values instead of value? 如何根…

二十、分水嶺算法

一、基本原理 分水嶺算法主要是基于距離變換&#xff08;distance transform&#xff09;&#xff0c;找到mark一些種子點&#xff0c;從這些種子點出發根據像素梯度變化進行尋找邊緣并標記 分水嶺&#xff1a;可以簡單的理解成一座山&#xff0c;然后來洪水了&#xff0c;水開…

細數WOW里暴雪的“親兒子”們

. 不知何時&#xff0c;魔獸世界的詞匯中忽然出現了一個新玩意&#xff1a;親兒子。雖說這個稱呼現在大多是拿來調侃法爺的&#xff0c;但江山代有兒子出&#xff0c;各領風騷一兩天&#xff0c;今天風光無限的法爺們也經歷過被其他職業壓得抬不起頭的小媳婦生涯。那么今天…

Linux下串口ttyS2,ttyS3不能用的問題解決辦法

PC104&#xff0c;Xlinux下&#xff0c;突然發現串口3,4不能用。。。 以為是硬件的問題&#xff0c;換成wince后&#xff0c;3,4工作正常&#xff0c;排除電路問題 在linux下查看dmesg: serial8250: ttyS0 at I/O 0x3f8 (irq 4) is a 16550Aserial8250: ttyS1 at I/O 0x2f8 (i…

安卓log.e函數打印示例_log1p()函數以及C ++中的示例

安卓log.e函數打印示例C log1p()函數 (C log1p() function) log1p() function is a library function of cmath header, it is used to get the natural logarithm (the base-e logarithm) of the one plus given value. It accepts a value (float, double, or long double) …

【C++grammar】C++類數據成員的初始化

目錄1、類成員的就地初始化example2、構造函數初始化3、默認構造函數&#xff1a;Default Constructor4、舉例5、成員的初始化方法的優先級1、類成員的就地初始化example class S { int m 7; // ok, copy-initializes m int n(7); // 錯誤&#xff1a;不允許用小括號初始化…

二十一、人臉檢測

一、識別圖像中的人臉 haarcascade_frontalface_alt_tree.xml lbpcascade_frontalcatface.xml GitHub上有Haar級聯檢測器源代碼可自行下載&#xff0c;lbp級聯檢測器也一樣有源碼可自行下載 也一樣 import cv2 as cv import numpy as npdef face_detect(image):gray cv.cvtC…