久精品国产欧美_国产精品乱码一区二区三区_国产一区在线观_国产精品久久77777_性色av一区二区三区_欧美精品第一页在线播放_欧美一区二区福利_国产精品视频久久久久_日韩精品伦理第一区_57pao成人永久免费视频

手機版 | 網站導航
東方科技網 綜合 >

要聞:3.自定義注解實現系統日志記載

博客園 | 2023-04-09 14:43:04


(資料圖)

前言

今天來分享一下我昨天的成果,昨天計劃復現若依系統的系統日志記載功能,若依的系統日志記載的主要實現使用過自定義注解配合切面類來實現的,這里會把標注@Log的方法在用戶調用完后,將方法的一部分信息記錄在數據庫的指定數據表中。因此我們需要java的spring開發四層結構:domain層、mapper層、service層、controller層。到這里項目就大概完成了,注意的是若依中自定義的工具類。本文的項目代碼鏈接:WomPlus: 結合若依項目對原始工單項目內容進行增強 (gitee.com),若依項目鏈接:GitHub - yangzongzhuan/RuoYi-fast: (RuoYi)官方倉庫 基于SpringBoot的權限管理系統 易讀易懂、界面簡潔美觀。 核心技術采用Spring、MyBatis、Shiro沒有任何其它重度依賴。直接運行即可用

1.系統日志記載開發流程五步走

朋友們可以根據自己的項目來調節數據表結構,domain類、mapper接口以及Mapper.xml、Service接口及其實現類,我這里是根據自己項目需求來編寫的。

1.1 根據自己項目創建數據表wo_operate_log
USE `wom_plus`DROP TABLE IF EXISTS `wo_operate_log`CREATE TABLE `wo_opertae_log`(    `operate_id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT "日志主鍵",    `title` VARCHAR(50) DEFAULT "" COMMENT "模塊標題",    `business_type` INT(2) DEFAULT 0 COMMENT "業務類型(0其它 1新增 2修改 3刪除)",    `method` VARCHAR(100) DEFAULT "" COMMENT "方法名稱",    `request_method` VARCHAR(10) DEFAULT "" COMMENT "請求方式",    `operator_type` INT(1) DEFAULT 0 COMMENT "操作類別(0其它 1后臺用戶 2手機端用戶)",    `operate_name` VARCHAR(50) DEFAULT "" COMMENT "操作人員",    `operate_url` VARCHAR(255) DEFAULT "" COMMENT "請求URL",    `operate_ip` VARCHAR(128) DEFAULT "" COMMENT "主機地址",    `operate_location` VARCHAR(255) DEFAULT "" COMMENT "操作地點",    `operate_param` VARCHAR(2000) DEFAULT "" COMMENT "請求參數",    `json_result` VARCHAR(2000) DEFAULT "" COMMENT "返回參數",    `status` INT(1) DEFAULT 0 COMMENT "操作狀態(0正常 1異常)",    `error_msg` VARCHAR(2000)   DEFAULT ""COMMENT "錯誤消息",    `operate_time` DATETIME COMMENT "操作時間",    `cost_time` BIGINT(20) DEFAULT 0 COMMENT "消耗時間",    PRIMARY KEY (operate_id),    KEY idx_sys_oper_log_bt (`business_type`),    KEY idx_sys_oper_log_s  (`status`),    KEY idx_sys_oper_log_ot (`operate_time`))ENGINE=INNODB COMMENT="操作日志記錄" DEFAULT CHARSET="utf8";
wo_operate_log1.2 根據自己項目編寫Operate實體類
/** * 操作日志記錄表 oper_log *  * @author ruoyi */public class OperateLog extends BaseEntity{    private static final long serialVersionUID = 1L;    /** 日志主鍵 */    @Excel(name = "操作序號", cellType = Excel.ColumnType.NUMERIC)    private Long operateId;    /** 操作模塊 */    @Excel(name = "操作模塊")    private String title;    /** 業務類型 */    @Excel(name = "業務類型", readConverterExp = "0=其它,1=新增,2=修改,3=刪除,4=授權,5=導出,6=導入,7=強退,8=生成代碼,9=清空數據")    private Integer businessType;        /** 業務類型數組 */    private Integer[] businessTypes;    /** 請求方法 */    @Excel(name = "請求方法")    private String method;    /** 請求方式 */    @Excel(name = "請求方式")    private String requestMethod;    /** 操作人類別 */    @Excel(name = "操作類別", readConverterExp = "0=其它,1=后臺用戶,2=手機端用戶")    private Integer operatorType;    /** 操作人員 */    @Excel(name = "操作人員")    private String operateName;//    /** 部門名稱 *///    @Excel(name = "部門名稱")//    private String deptName;    /** 請求url */    @Excel(name = "請求地址")    private String operateUrl;    /** 操作地址 */    @Excel(name = "操作地址")    private String operateIp;    /** 操作地點 */    @Excel(name = "操作地點")    private String operateLocation;    /** 請求參數 */    @Excel(name = "請求參數")    private String operateParam;    /** 返回參數 */    @Excel(name = "返回參數")    private String jsonResult;    /** 狀態0正常 1異常 */    @Excel(name = "狀態", readConverterExp = "0=正常,1=異常")    private Integer status;    /** 錯誤消息 */    @Excel(name = "錯誤消息")    private String errorMsg;    /** 操作時間 */    @Excel(name = "操作時間", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")    private Date operTime;    /** 消耗時間 */    @Excel(name = "消耗時間", suffix = "毫秒")    private Long costTime;    public static long getSerialVersionUID() {        return serialVersionUID;    }    public Long getOperateId() {        return operateId;    }    public void setOperateId(Long operateId) {        this.operateId = operateId;    }    public String getTitle() {        return title;    }    public void setTitle(String title) {        this.title = title;    }    public Integer getBusinessType() {        return businessType;    }    public void setBusinessType(Integer businessType) {        this.businessType = businessType;    }    public Integer[] getBusinessTypes() {        return businessTypes;    }    public void setBusinessTypes(Integer[] businessTypes) {        this.businessTypes = businessTypes;    }    public String getMethod() {        return method;    }    public void setMethod(String method) {        this.method = method;    }    public String getRequestMethod() {        return requestMethod;    }    public void setRequestMethod(String requestMethod) {        this.requestMethod = requestMethod;    }    public Integer getOperatorType() {        return operatorType;    }    public void setOperatorType(Integer operatorType) {        this.operatorType = operatorType;    }    public String getOperateName() {        return operateName;    }    public void setOperateName(String operateName) {        this.operateName = operateName;    }    public String getOperateUrl() {        return operateUrl;    }    public void setOperateUrl(String operateUrl) {        this.operateUrl = operateUrl;    }    public String getOperateIp() {        return operateIp;    }    public void setOperateIp(String operateIp) {        this.operateIp = operateIp;    }    public String getOperateLocation() {        return operateLocation;    }    public void setOperateLocation(String operateLocation) {        this.operateLocation = operateLocation;    }    public String getOperateParam() {        return operateParam;    }    public void setOperateParam(String operateParam) {        this.operateParam = operateParam;    }    public String getJsonResult() {        return jsonResult;    }    public void setJsonResult(String jsonResult) {        this.jsonResult = jsonResult;    }    public Integer getStatus() {        return status;    }    public void setStatus(Integer status) {        this.status = status;    }    public String getErrorMsg() {        return errorMsg;    }    public void setErrorMsg(String errorMsg) {        this.errorMsg = errorMsg;    }    public Date getOperateTime() {        return operTime;    }    public void setOperateTime(Date operateTime) {        this.operTime = operateTime;    }    public Long getCostTime() {        return costTime;    }    public void setCostTime(Long costTime) {        this.costTime = costTime;    }    @Override    public String toString() {        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)            .append("operateId", getOperateId())            .append("title", getTitle())            .append("businessType", getBusinessType())            .append("businessTypes", getBusinessTypes())            .append("method", getMethod())            .append("requestMethod", getRequestMethod())            .append("operatorType", getOperatorType())            .append("operateName", getOperateName())            .append("operateUrl", getOperateUrl())            .append("operateIp", getOperateIp())            .append("operateLocation", getOperateLocation())            .append("operateParam", getOperateParam())            .append("status", getStatus())            .append("errorMsg", getErrorMsg())            .append("operateTime", getOperateTime())            .append("costTime", getCostTime())            .toString();    }}
OperateLog1.3 根據自己項目編寫OperateMapper和OperateMapper.xml
public interface OperateLogMapper {    /**     * 新增操作日志     * @param :operateLog 操作日志對象     */    public void insertOperateLog(OperateLog operateLog);    /**     * 查詢系統操作日志集合     * @param :operateLog 操作日志對象     * @return 操作日志集合     */    public List selectOperateLogList(OperateLog operateLog);    /**     * 批量刪除系統操作日志     * @param ids 需要刪除的數據     * @return 結果     */    public int deleteOperateLogByIds(String[] ids);    /**     * 查詢操作日志詳細     * @param :operateId 操作ID     * @return 操作日志對象     */    public OperateLog selectOperateLogById(Long operateId);    /**     * 清空操作日志     */    public void cleanOperateLog();}                                                                                                                                                    select operate_id, title, business_type, method, request_method, operator_type, operate_name, operate_url, operate_ip, operate_location, operate_param, json_result, status, error_msg, operate_time, cost_time        from wom_plus.wo_operate_log                  insert into wom_plus.wo_operate_log(title, business_type, method, request_method, operator_type, operate_name, operate_url, operate_ip, operate_location, operate_param, json_result, status, error_msg, cost_time, operate_time)        values (#{title}, #{businessType}, #{method}, #{requestMethod}, #{operatorType}, #{operateName}, #{operateUrl}, #{operateIp}, #{operateLocation}, #{operateParam}, #{jsonResult}, #{status}, #{errorMsg}, #{costTime}, sysdate())                   delete from wom_plus.wo_operate_log where operate_id in                    #{operateId}                                truncate table wo_operate_log    
Mapper接口及其SQL1.4 根據自己項目編寫IOperateService和OperateServiceImpl
public interface IOperateLogService {    /**     * 新增操作日志     *     * @param :operateLog 操作日志對象     */    public void insertOperateLog(OperateLog operateLog);    /**     * 查詢系統操作日志集合     *     * @param :operateLog 操作日志對象     * @return 操作日志集合     */    public List selectOperateLogList(OperateLog operateLog);    /**     * 批量刪除系統操作日志     *     * @param ids 需要刪除的數據     * @return 結果     */    public int deleteOperateLogByIds(String ids);    /**     * 查詢操作日志詳細     *     * @param operateId 操作ID     * @return 操作日志對象     */    public OperateLog selectOperateLogById(Long operateId);    /**     * 清空操作日志     */    public void cleanOperateLog();}@Servicepublic class OperateLogServiceImpl implements IOperateLogService {    @Autowired(required = false)    private OperateLogMapper operateLogMapper;    @Override    public void insertOperateLog(OperateLog operateLog) {        operateLogMapper.insertOperateLog(operateLog);    }    @Override    public List selectOperateLogList(OperateLog operateLog) {        return operateLogMapper.selectOperateLogList(operateLog);    }    @Override    public int deleteOperateLogByIds(String ids) {        return deleteOperateLogByIds(ids);    }    @Override    public OperateLog selectOperateLogById(Long operateId) {        return operateLogMapper.selectOperateLogById(operateId);    }    @Override    public void cleanOperateLog() {        operateLogMapper.cleanOperateLog();    }}
IoperateService及其實現類1.5 Controller方法上的@Log
@Log(title = "用戶管理", businessType = BusinessType.EXPORT)@PostMapping("/export")@ResponseBodypublic AjaxResult export(@RequestParam(value = "name", required = false) String username){    List list = userDetailsService.getUserListByUsername(username);    ExcelUtil util = new ExcelUtil<>(SysUser.class);    return util.exportExcel(list, "用戶數據");}
2.自定義系統日志記載注解及其切面實現

java中注解與AOP的結合,方便了廣大java程序員對應用的開發,能夠對原有方法的增強減少很多代碼,原來的我們如果要在每個方法上面進行日志記載,那么需要每個方法都調用日志記載的方法,而現在我們只需要在需要日志加載的方法上面加上@ Log就完美快速簡單地解決了上述繁雜問題。

2.1 自定義@Log
/** * 自定義操作日志記錄注解 *  * @author ruoyi * */@Target({ ElementType.PARAMETER, ElementType.METHOD })//作用于方法和參數上面@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Log{    /**     * 模塊     */    public String title() default "";    /**     * 功能     */    public BusinessType businessType() default BusinessType.OTHER;    /**     * 操作人類別     */    public OperatorType operatorType() default OperatorType.MANAGE;    /**     * 是否保存請求的參數     */    public boolean isSaveRequestData() default true;    /**     * 是否保存響應的參數     */    public boolean isSaveResponseData() default true;    /**     * 排除指定的請求參數     */    public String[] excludeParamNames() default {};}
@Log2.2 LogAspect(重點)

該類就是根據動態代理來實現的,在Spring中稱之為AOP,面向切面編程,可以很好地實現對軟件中已有方法在安全、日志、監控等方面的增強。

@Component@Aspect/** * 操作日志記錄處理 */public class LogAspect {    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);    /** 排除敏感屬性字段 */    public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };    /** 計算操作消耗時間 */    private static final ThreadLocal TIME_THREADLOCAL = new NamedThreadLocal("Cost Time");    /**     * 處理請求前執行     */    @Before(value = "@annotation(controllerLog)")    //該方法傳入一個注解類型參數,改參數被@Before注解中的@annotation作用,    // 表示只要該注解作用在哪個方法上,就在該方法上生效    public void before(JoinPoint joinPoint, Log controllerLog){        TIME_THREADLOCAL.set(System.currentTimeMillis());    }    /**     * 處理完請求后執行     * @param joinPoint 切點     */    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")    public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult)    {        handleLog(joinPoint, controllerLog, null, jsonResult);    }    /**     * 攔截異常操作     * @param joinPoint 切點     * @param e 異常     */    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e)    {        handleLog(joinPoint, controllerLog, e, null);    }    protected void handleLog(final JoinPoint joinPoint, Log controllerLog,                             final Exception e, Object jsonResult){        try        {            //本項目沒有使用shiro框架,所以無法根據登錄獲取用戶信息,以后再完善//            // 獲取當前的用戶//            SysUser currentUser = ShiroUtils.getSysUser();            // *========數據庫日志=========*//            OperateLog operateLog = new OperateLog();            //ordinal可以返回當前枚舉所在的序列,利用這個函數,可以自增長的獲取我們定義的Excel的cell位置,            // 然后進行寫入數據操作            operateLog.setStatus(BusinessStatus.SUCCESS.ordinal());            // 請求的地址//            String ip = ShiroUtils.getIp();//這里暫時不使用Shiro相關類            String ip = IPUtils.getIpAddr(ServletUtils.getRequest());            operateLog.setOperateIp(ip);            operateLog.setOperateUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));            //后面完善//            if (currentUser != null)//            {//                operateLog.setOperateName(currentUser.getUsername());//            }            operateLog.setOperateName("xiaoku");            if (e != null)            {                operateLog.setStatus(BusinessStatus.FAIL.ordinal());                operateLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));            }            // 設置方法名稱            String className = joinPoint.getTarget().getClass().getName();            String methodName = joinPoint.getSignature().getName();            operateLog.setMethod(className + "." + methodName + "()");            // 設置請求方式            operateLog.setRequestMethod(ServletUtils.getRequest().getMethod());            // 處理設置注解上的參數            getControllerMethodDescription(joinPoint, controllerLog, operateLog, jsonResult);            // 設置消耗時間            operateLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());            //我這里不使用異步任務,因此在這里執行插入            //這里通過SpringUtils.getBean(Classclz)來獲取所需對象            // 遠程查詢操作地點            operateLog.setOperateLocation(AddressUtils.getRealAddressByIP(operateLog.getOperateIp()));            SpringUtils.getBean(IOperateLogService.class).insertOperateLog(operateLog);            //暫時不需要//            // 保存數據庫//            AsyncManager.me().execute(AsyncFactory.recordOper(operLog));        }        catch (Exception exp)        {            // 記錄本地異常日志            log.error("異常信息:{}", exp.getMessage());            exp.printStackTrace();        }        finally        {            TIME_THREADLOCAL.remove();        }    }    /**     * 獲取注解中對方法的描述信息 用于Controller層注解     * @param log 日志     * @param :operateLog 操作日志     * @throws Exception     */    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, OperateLog operLog, Object jsonResult) throws Exception    {        // 設置action動作        operLog.setBusinessType(log.businessType().ordinal());        // 設置標題        operLog.setTitle(log.title());        // 設置操作人類別        operLog.setOperatorType(log.operatorType().ordinal());        // 是否需要保存request,參數和值        if (log.isSaveRequestData())        {            // 獲取參數的信息,傳入到數據庫中。            setRequestValue(joinPoint, operLog, log.excludeParamNames());        }        // 是否需要保存response,參數和值        if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult))        {            operLog.setJsonResult(StringUtils.substring(JSONObject.toJSONString(jsonResult), 0, 2000));        }    }    /**     * 獲取請求的參數,放到log中     *     * @param : operateLog     * @param : request     */    private void setRequestValue(JoinPoint joinPoint, OperateLog operLog, String[] excludeParamNames)    {        Map map = ServletUtils.getRequest().getParameterMap();        if (StringUtils.isNotEmpty(map))        {            String params = JSONObject.toJSONString(map, excludePropertyPreFilter(excludeParamNames));            operLog.setOperateParam(StringUtils.substring(params, 0, 2000));        }        else        {            Object args = joinPoint.getArgs();            if (StringUtils.isNotNull(args))            {                String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);                operLog.setOperateParam(StringUtils.substring(params, 0, 2000));            }        }    }    /**     * 忽略敏感屬性     */    public PropertyPreFilters.MySimplePropertyPreFilter excludePropertyPreFilter(String[] excludeParamNames)    {        return new PropertyPreFilters().addFilter().addExcludes(ArrayUtils.addAll(EXCLUDE_PROPERTIES, excludeParamNames));    }    /**     * 參數拼裝     */    private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames)    {        String params = "";        if (paramsArray != null && paramsArray.length > 0)        {            for (Object o : paramsArray)            {                if (StringUtils.isNotNull(o) && !isFilterObject(o))                {                    try                    {                        Object jsonObj = JSONObject.toJSONString(o, excludePropertyPreFilter(excludeParamNames));                        params += jsonObj.toString() + " ";                    }                    catch (Exception e)                    {                    }                }            }        }        return params.trim();    }    /**     * 判斷是否需要過濾的對象。     * @param o 對象信息。     * @return 如果是需要過濾的對象,則返回true;否則返回false。     */    @SuppressWarnings("rawtypes")    public boolean isFilterObject(final Object o)    {        Class clazz = o.getClass();        if (clazz.isArray())        {            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);        }        else if (Collection.class.isAssignableFrom(clazz))        {            Collection collection = (Collection) o;            for (Object value : collection)            {                return value instanceof MultipartFile;            }        }        else if (Map.class.isAssignableFrom(clazz))        {            Map map = (Map) o;            for (Object value : map.entrySet())            {                Map.Entry entry = (Map.Entry) value;                return entry.getValue() instanceof MultipartFile;            }        }        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse                || o instanceof BindingResult;    }}
LogAspect

上述代碼中的前置通知@Before和后置通知@After是用來記錄標注有@Log注解的方法運行所花費的時間,環繞返回注解@AroundReturning是返回系統日志記載信息,環繞異常注解@AroundThrowing是返回這部分代碼出現異常是返回的異常信息。主要的日志系統信息實現是在handleLog()方法中,根據切點獲取方法名稱、請求參數、等等信息。

2.3 若依中的自定義工具類3.項目運行結果

第一張圖的運行結果是使用@Log注解標注在以Excel形式導出數據的export()方法上面,第二張圖片是系統日志記載表wo_operate_log記載的執行標有@Log注解的方法的日志記載信息。我這里只截取了后面的內容。

關鍵詞:

上一篇:

下一篇:

相關推薦

媒體焦點

久精品国产欧美_国产精品乱码一区二区三区_国产一区在线观_国产精品久久77777_性色av一区二区三区_欧美精品第一页在线播放_欧美一区二区福利_国产精品视频久久久久_日韩精品伦理第一区_57pao成人永久免费视频
日本欧美黄色片| 日本黄色三级大片| 午夜免费一区二区| 99精品在线免费视频| 8x8ⅹ国产精品一区二区二区| 99精品999| 中文字幕一区久久| 亚洲无在线观看| 欧美丝袜在线观看| 五月六月丁香婷婷| 国产高清精品软男同| 91精品视频国产| √天堂资源在线| 午夜激情视频网| 玖玖精品在线视频| 黄色激情在线视频| 色欲av无码一区二区人妻| 男女猛烈激情xx00免费视频| 女人被男人躁得好爽免费视频| av 日韩 人妻 黑人 综合 无码| 成年人视频网站免费| 欧美黄色免费网址| 欧美三级在线观看视频| 青青在线视频观看| 99re精彩视频| 欧美精品一区二区性色a+v| 大桥未久一区二区| av无码久久久久久不卡网站| 美女日批免费视频| 牛夜精品久久久久久久| 伊人色在线视频| 麻豆一区二区三区在线观看| 日韩欧美猛交xxxxx无码| 国产中文字幕视频在线观看| 免费激情视频在线观看| av中文字幕网址| 免费观看中文字幕| 91九色在线观看视频| 15—17女人毛片| 9色视频在线观看| 黄色网页免费在线观看| 三级a三级三级三级a十八发禁止| 91制片厂免费观看| 国产91在线免费| 中文字幕国产高清| 国产女主播自拍| 九色91popny| 精品人妻大屁股白浆无码| 欧美成人精品欧美一级乱| 国产欧美精品一二三| www.av毛片| 成年网站在线播放| 国产91沈先生在线播放| 久久精品影视大全| 日b视频免费观看| 污网站免费在线| 免费超爽大片黄| 亚洲精品综合在线观看| 国产欧美日韩网站| 欧美伦理视频在线观看| 精品国产一区二区三区在线| 国产女女做受ⅹxx高潮| www.久久com| 十八禁视频网站在线观看| 强伦女教师2:伦理在线观看| 免费日韩视频在线观看| 日本大胆人体视频| 三级a三级三级三级a十八发禁止| 日韩精品一区二区免费| 亚洲黄色片免费| 国语对白做受xxxxx在线中国| 自拍偷拍视频在线| 男人搞女人网站| 丰满的少妇愉情hd高清果冻传媒| 四季av一区二区三区| 777米奇影视第四色| 欧美中文字幕在线观看视频| 国产成人美女视频| 黄色一级一级片| 国产中文字幕乱人伦在线观看| 最新天堂在线视频| av动漫免费看| 人妻少妇精品无码专区二区| 大桥未久一区二区三区| 日本高清久久久| 99精品免费在线观看| 亚洲国产精品无码av| 国产91av视频在线观看| 三上悠亚av一区二区三区| 农村妇女精品一二区| 欧美啪啪免费视频| 免费看欧美一级片| 国产经典久久久| 在线播放 亚洲| 日本美女视频一区| 日本激情视频在线播放| 玩弄japan白嫩少妇hd| 久久久久久久久久久视频| 男人天堂av片| 东北少妇不带套对白| 国产又粗又猛又爽又黄的网站| 日本在线播放一区二区| 国产成人精品无码播放| 黑人糟蹋人妻hd中文字幕 | 影音先锋成人资源网站| 中国黄色片一级| www.久久久精品| jizzzz日本| 亚洲免费999| 视频免费1区二区三区| 一区二区在线免费看| 亚洲涩涩在线观看| 污污的网站免费| 亚洲精品成人在线播放| 中文字幕成人免费视频| 最新av免费在线观看| 超碰91在线播放| 青青草原网站在线观看| 国产爆乳无码一区二区麻豆| 久久精品无码中文字幕| 少妇人妻无码专区视频| 国产成人在线免费看| 免费在线观看的毛片| 三年中国国语在线播放免费| 性chinese极品按摩| 日韩精品aaa| 伊人网在线免费| 国产精品又粗又长| 国产精品亚洲二区在线观看 | 波多野结衣家庭教师在线播放| 日本韩国欧美在线观看| 国产成人久久婷婷精品流白浆| 99草草国产熟女视频在线| 黄大色黄女片18第一次| 国产精品无码乱伦| 日韩免费在线观看av| 青青草原成人网| 天天干天天综合| 免费观看黄色大片| 国产精品久久久久久久乖乖| www国产黄色| 色婷婷综合网站| 亚洲精品成人在线播放| 最新av网址在线观看| 欧美日韩一道本| jizzzz日本| 久久精品在线免费视频| 日韩精品―中文字幕| 青青青国产在线视频| 91视频福利网| 水蜜桃色314在线观看| 国产又粗又长又大的视频| 精品久久免费观看| 蜜臀av无码一区二区三区| 亚洲男人天堂色| 玖玖精品在线视频| 老熟妇仑乱视频一区二区| 日韩不卡的av| 欧美a在线视频| 夜夜爽久久精品91| 日本福利视频在线| 久久久福利影院| 国产最新免费视频| 亚洲一级片免费观看| 91精品91久久久中77777老牛| 玖玖爱视频在线| 拔插拔插海外华人免费| 91制片厂毛片| 人妻久久久一区二区三区| 不卡的av中文字幕| 18禁网站免费无遮挡无码中文| 三上悠亚在线一区| 大j8黑人w巨大888a片| 久久综合在线观看| 国产熟女高潮视频| 日韩中文字幕在线不卡| 日本久久久久久久久久久久| 日韩日韩日韩日韩日韩| 激情成人在线观看| 簧片在线免费看| 乱妇乱女熟妇熟女网站| 在线观看污视频| 中文字幕色网站| 无人在线观看的免费高清视频| 欧美中文字幕在线观看视频| 天堂av8在线| 欧美黑人又粗又大又爽免费| 最近免费观看高清韩国日本大全| 99久久久无码国产精品6| 99热这里只有精品免费| 亚洲天堂国产视频| 国产精品无码一本二本三本色| 久久国产午夜精品理论片最新版本| 手机在线国产视频| 久久久久国产一区| 日韩毛片在线免费看| 全黄性性激高免费视频| 日韩一二区视频| 自拍偷拍一区二区三区四区| caopor在线视频|