整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          Spring MVC之LocaleResolver詳

          Spring MVC之LocaleResolver詳解

          對于LocaleResolver,其主要作用在于根據(jù)不同的用戶區(qū)域展示不同的視圖,而用戶的區(qū)域也稱為Locale,該信息是可以由前端直接獲取的。通過這種方式,可以實現(xiàn)一種國際化的目的,比如針對美國用戶可以提供一個視圖,而針對中國用戶則可以提供另一個視圖。本文主要講解如果使用LocaleResolver來實現(xiàn)對用戶不同視圖切換的目的。

          LocaleResolver是Spring提供的一個接口,其聲明如下:

          public interface LocaleResolver {
           // 根據(jù)request對象根據(jù)指定的方式獲取一個Locale,如果沒有獲取到,則使用用戶指定的默認(rèn)的Locale
          	Locale resolveLocale(HttpServletRequest request);
           
           // 用于實現(xiàn)Locale的切換。比如SessionLocaleResolver獲取Locale的方式是從session中讀取,但如果
           // 用戶想要切換其展示的樣式(由英文切換為中文),那么這里的setLocale()方法就提供了這樣一種可能
          	void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, 
           @Nullable Locale locale);
          }
          

          針對LocaleResolver,Spring提供了幾種實現(xiàn)方式,分別如下:

          • FixedLocaleResolver:在聲明該resolver時,需要指定一個默認(rèn)的Locale,在進(jìn)行Locale獲取時,始終返回該Locale,并且調(diào)用其setLocale()方法也無法改變其Locale;
          • CookieLocaleResolver:其讀取Locale的方式是在session中通過Cookie來獲取其指定的Locale的,如果修改了Cookie的值,頁面視圖也會同步切換;
          • SessionLocaleResolver:其會將Locale信息存儲在session中,如果用戶想要修改Locale信息,可以通過修改session中對應(yīng)屬性的值即可;
          • AcceptHeaderLocaleResolver:其會通過用戶請求中名稱為Accept-Language的header來獲取Locale信息,如果想要修改展示的視圖,只需要修改該header信息即可。

          需要說明的是,Spring雖然提供的幾個不同的獲取Locale的方式,但這些方式處理FixedLocaleResolver以外,其他幾個也都支持在瀏覽器地址欄中添加locale參數(shù)來切換Locale。對于Locale的切換,Spring是通過攔截器來實現(xiàn)的,其提供了一個LocaleChangeInterceptor,在該攔截器中的preHandle()方法中,Spring會讀取瀏覽器參數(shù)中的locale參數(shù),然后調(diào)用LocaleResolver.setLocale()方法來實現(xiàn)對Locale的切換。

          這里我們以CookieLocaleResolver為例來講解如何通過不同的Locale展示不同的視圖。首先是我們的xml文件配置:

          <context:component-scan base-package="mvc"/>
           <mvc:annotation-driven/>
           <mvc:interceptors>
           <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
           <bean class="mvc.interceptor.MyHandlerInterceptor"/>
           </mvc:interceptors>
           <bean class="org.springframework.web.servlet.view.ResourceBundleViewResolver"/>
           <bean id="localeResolver" 
           class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
           <property name="defaultLocale" value="zh_CN"/>
           </bean>
          

          關(guān)于上述配置有三點需要說明:

          • 指定了使用的LocaleResolver為CookieLocaleResolver,并且defaultLocale指定為zh_CN,需要注意的是,Spring中LocaleResolver的bean名稱必須為localeResolver,因為Spring讀取該bean時是通過該名稱讀取的;
          • 上述配置總還指定了ViewResolver為ResourceBundleViewResolver,這里不能使用InternalResourceViewResolver,因為其不支持通過不同的Locale進(jìn)行不同的視圖切換,而ResourceBundleViewResolver是支持的;
          • 配置中添加了LocaleChangeInterceptor的攔截器,用于對Locale的切換,如果不需要Locale切換的功能,可以不指定該攔截器。

          對于后臺接口的聲明,其與一般的接口聲明是沒有區(qū)別的。如下是我們聲明的一個接口:

          @Controller
          @RequestMapping("/user")
          public class UserController {
           @Autowired
           private UserService userService;
           @RequestMapping(value="/detail", method=RequestMethod.GET)
           public ModelAndView detail(@RequestParam("id") long id, 
           @ModelAttribute("message") String message, Locale locale) {
           System.out.println(message);
           ModelAndView view=new ModelAndView("user");
           User user=userService.detail(id);
           view.addObject("user", user);
           view.addObject("locale", locale);
           return view;
           }
          }
          

          上述接口返回的視圖為user,并且將當(dāng)前用戶的Locale信息返回給了前端,可以看到,這里獲取Locale數(shù)據(jù)的方式就只需要簡單的聲明一個類型為Locale的參數(shù)即可。

          關(guān)于視圖的展示,由于我們需要根據(jù)不同的Locale展示不同的視圖,而在上述接口中,我們暫時沒發(fā)現(xiàn)這樣的路由。實際上,這個路由是通過ResourceBundleViewResolver類實現(xiàn)的,在使用該ViewResovler時,其會到class路徑下查找名稱為views的Resource Bundle,并且通過用戶指定的Locale,唯一定位到某個Resource Bundle。然后在該Resource Bundle中查找指定的視圖信息,比如這里接口返回的視圖為user,那么就會在獲取到的Resource Bundle查找user.(class)和user.url信息,這里user.(class)指定了展示該視圖所需要的View對象的,而user.url則指定了具體的視圖位置。比如如下配置的就是Locale分別為zh_CN和en_US的視圖:

          # views_zh_CN.properties
          user.(class)=org.springframework.web.servlet.view.InternalResourceView
          user.url=/WEB-INF/view/user_zh_CN.jsp
          # views_en_US.properties
          user.(class)=org.springframework.web.servlet.view.InternalResourceView
          user.url=/WEB-INF/view/user_en_US.jsp
          

          通過這種方式,ResourceBundleViewResolver就實現(xiàn)了針對不同的Locale來展示不同的視圖的目的。如下是我們編寫的兩個分別用于zh_CN和en_US視圖展示的jsp頁面:

          <!-- user_zh_CN.jsp -->
          <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
          <%@ page contentType="text/html;charset=UTF-8" language="java" %>
          <html>
          <head>
           <title>User Jsp-zh CN</title>
          </head>
          <body>
          ${user.id} ${user.name} ${user.age} ${locale}
          </body>
          </html>
          <!-- user_en_US.jsp -->
          <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
          <%@ page contentType="text/html;charset=UTF-8" language="java" %>
          <html>
          <head>
           <title>User Jsp-en US</title>
          </head>
          <body>
          ${user.id} ${user.name} ${user.age} ${locale}
          </body>
          </html>
          

          啟動上述程序,我們在瀏覽器中鍵入http://localhost:8080/user/detail?id=1,可以看到其展示了如下視圖:

          1 Bob 27 zh_CN
          

          如果我們添加名稱為org.springframework.web.servlet.i18n.CookieLocaleResolver.LOCALE,值為en_US的cookie,那么其展示的頁面切換如下:

          1 Bob 27 en_US
          

          這說明我們成功使用Cookie對Locale進(jìn)行了切換。如果我們在瀏覽器地址欄中添加locale=zh_CN的參數(shù),可以看到,頁面展示又切換為了前面那種情況。

          本文主要對LocaleResolver進(jìn)行了講解,并且演示了如何通過配置不同的LocaleResolver來達(dá)到實現(xiàn)展示不同的視圖的目的。需要注意的是,我們的LocaleResolver的bean名稱必須為localeResolver,并且需要指定的ViewResolver輔以支持,否則切換的視圖可能無法正常工作。

          度分析

          雖然但是聽到這個消息的時候,內(nèi)心還是挺震驚的,畢竟是一個完整的管理系統(tǒng),功能界面還不能太過簡陋。而且從數(shù)據(jù)庫設(shè)計到整個系統(tǒng)的交付全由自己一人完成,挑戰(zhàn)效果直接拉滿!但是冷靜下來思考一下,其實也并不是很難,整體的項目流程即為:設(shè)計——>文檔——>編碼——>交付。整體的流程劃清之后,就開始一步步從無到有的實現(xiàn),沒想到到最后一步的時候,我竟然才用一天半的時間!!后面又用了半天的時間對整體的項目做了一個優(yōu)化處理!

          項目回顧

          最終效果演示:

          技術(shù)選型:

          • SpringBoot
          • Thymeleaf
          • Mybatis-Plus
          • MySQL
          • PageHelper
          • Lombok
          • Redis(后期頁面優(yōu)化使用)

          項目業(yè)務(wù)流程簡介

          登錄模塊、用戶模塊管理以及對用戶的角色分配,新聞公告模塊的管理、商品模塊(包括對商品、商品分類、訂單)的管理、角色模塊的管理;對于前端某資源是否有權(quán)限操作該資源,使用的是thymeleaf模板語法進(jìn)行判斷鑒別以及文件上傳等基本功能。

          項目搭建(使用模板引擎)

          1. 首先創(chuàng)建Maven項目

          引入相應(yīng)的依賴,構(gòu)建所需文件目錄

          2. 編寫yaml配置文件

          server:
            port: 8080
          
          spring:
            datasource:
              driver-class-name: com.mysql.cj.jdbc.Driver
              url: jdbc:mysql://localhost:3306/supplier?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
              username: root
              password: root
            # thymeleaf 配置
            thymeleaf:
              # 關(guān)閉緩存
              cache: false
              prefix: classpath:/templates/
          
          mybatis-plus:
            mapper-locations: classpath*:/mapper/**/*.xml
          

          3. 項目初期基本搭建

          在搭建一個項目的初期,為了讓系統(tǒng)顯得更規(guī)范化,我一般會提前做好基礎(chǔ)的配置和聲明,一個項目從開始設(shè)想時所涉及到技術(shù)以及這些技術(shù)對應(yīng)的一些基礎(chǔ)配置,都要提前規(guī)劃清楚(個人習(xí)慣)。比如:異常處理、攔截器、過濾器、常量類等等。

          ①異常處理

          @ControllerAdvice
          public class ExceptionHandler {
          
              private final org.slf4j.Logger logger=LoggerFactory.getLogger(this.getClass());
          
              @org.springframework.web.bind.annotation.ExceptionHandler(Exception.class)
              public ModelAndView exception(HttpServletRequest request, Exception e ) throws Exception {
                  logger.error("Request URL:{},Exception:{}",request.getRequestURL(),e);
          
                  if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class )!=null){
                      throw e;
                  }
          
                  ModelAndView mv=new ModelAndView();
                  mv.addObject("url",request.getRequestURL());
                  mv.addObject("exception",e);
                  mv.setViewName("error/error");
          
                  return mv;
              }
          }
          

          ② 攔截器

          攔截器主要是對一些資源做的處理,類似于某些資源需要用戶登錄后才能訪問的,某些是不需要的,比如:登錄功能就不需要有所攔截,而對用戶的各種管理就需要添加攔截操作,這樣才能使系統(tǒng)的安全性有所提高。

          登錄攔截

          public class LoginInterceptor extends HandlerInterceptorAdapter {
          
              @Override
              public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
                  if (request.getSession().getAttribute("user")==null){
                      response.sendRedirect("/api");
                      return false;
                  }
                  return true;
              }
          }
          

          資源放行

          @Configuration
          public class WebConfig extends WebMvcConfigurerAdapter {
          
              @Override
              public void addInterceptors(InterceptorRegistry registry) {
                  registry.addInterceptor(new LoginInterceptor())
                          .addPathPatterns("/api/**")
                          .excludePathPatterns("/api","/api/doLogin");
              }
          }
          

          4. 編寫Controller前端控制器代碼

          首先創(chuàng)建一個FileController類

          ① 跳轉(zhuǎn)文件上傳的頁面

          //跳轉(zhuǎn)文件上傳的頁面
          @RequestMapping("/file-upload")
          public String userList(){
            return "file-upload";
          }
          

          ② 實現(xiàn)文件上傳的功能

          @RequestMapping("/doAddForUser")
          public String doAdd(User user, @RequestParam("file") MultipartFile files, HttpServletRequest request) throws IOException {
            //String path=null;
            if (files !=null && !files.isEmpty()){
              String name=UUID.randomUUID().toString().replace("-","");
              //獲取文件的擴(kuò)展名
              String ext=FilenameUtils.getExtension(files.getOriginalFilename());
              //設(shè)置文件上傳的路徑
              String url=request.getSession().getServletContext().getRealPath("/upload/");
          
              File file=new File(url);
              if (!file.exists()){
                file.mkdir();
              }
              //測試路徑
              System.out.println(request.getServletPath()+ "/upload");
              System.out.println(request.getContextPath() + "/upload/");
              //以絕對路徑保存重命名后的文件
              files.transferTo(new File(url+"/"+name+"."+ext));
              user.setAvatar(request.getContextPath() + "/upload/"+name+"."+ext);
            }
          
            user.setId(UUID.randomUUID().toString());
            String salt=PasswordUtils.getSalt();
            String password=user.getPassword();
            String encode=PasswordUtils.encode(password, salt);
            user.setSalt(salt) ;
            user.setPassword(encode);
            user.setCreateTime(new Date());
            userService.save(user);
            return "redirect:/api/users";
          }
          

          注:如何想要實現(xiàn)多文件上傳需要更改的地方如下:

          ③ 實現(xiàn)多文件上傳功能

          在這個項目中并未實現(xiàn)多文件上傳功能

          private void commons(Object obj, @RequestParam("file") CommonsMultipartFile[] files, HttpServletRequest request) throws IOException {
              //String path=null;
              for (int i=0; i < files.length; i++) {
          
                  if (files[i] !=null && !files[i].isEmpty()){
                      String name=UUID.randomUUID().toString().replace("-","");
                      //獲取文件的擴(kuò)展名
                      String ext=FilenameUtils.getExtension(files[i].getOriginalFilename());
                      //設(shè)置文件上傳的路徑
                      String url=request.getSession().getServletContext().getRealPath("/upload/");
          
                      File file=new File(url);
                      if (!file.exists()){
                          file.mkdir();
                      }
                      //測試路徑
                      System.out.println(request.getServletPath()+ "/upload");
                      System.out.println(request.getContextPath() + "/upload/");
                      //以絕對路徑保存重命名后的文件
                      files[i].transferTo(new File(url+"/"+name+"."+ext));
          
                      if (i==0){
                          obj.setUrl1(request.getContextPath() + "/upload/"+name+"."+ext);
                      }
                      if (i==1){
                          obj.setUrl2(request.getContextPath() + "/upload/"+name+"."+ext);
                      }
                      if (i==2){
                          obj.setUrl3(request.getContextPath() + "/upload/"+name+"."+ext);
                      }
                      if (i==3){
                          obj.setUrl4(request.getContextPath() + "/upload/"+name+"."+ext);
                      }
                      if (i==4){
                          obj.setUrl5(request.getContextPath() + "/upload/"+name+"."+ext);
                      }
                  }
              }
          }
          

          5. 項目優(yōu)化

          對于前后端不分離的項目,多數(shù)使用的是頁面緩存優(yōu)化,當(dāng)系統(tǒng)某一瞬間遭受巨大流量時,當(dāng)?shù)谝粋€用戶進(jìn)行頁面訪問時可以將該頁面數(shù)據(jù)進(jìn)行緩存,這樣,后來的用戶訪問到的頁面都是從緩存中獲取的,這樣就減少了 對數(shù)據(jù)庫的操作,減輕了數(shù)據(jù)庫的壓力,從而達(dá)到優(yōu)化的處理。

          ① 導(dǎo)入依賴

          <!--Redis-->
          <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
          </dependency>
          <!--commons-pools2 對象池依賴-->
          <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
          </dependency>
          

          ② yaml配置

          ## Redis配置
            redis:
              # 服務(wù)器地址
              host: localhost
              # 端口
              port: 6379
              # 數(shù)據(jù)庫
              database: 0
              # 超時時間
              connect-timeout: 10000ms
              lettuce:
                pool:
                  # 最大連接數(shù)
                  max-active: 8
                  # 最大連接阻塞等待時間 默認(rèn) -1
                  max-wait: 10000ms
                  # 最大空閑時間 默認(rèn)8
                  max-idle: 200
                  # 最小空閑連接 默認(rèn)8
                  min-idle: 5
          

          ④ Redis序列化處理

          @Configuration
          public class RedisConfig {
          
              @Bean
              public RedisTemplate<String,Object>  redisTemplate(RedisConnectionFactory redisConnectionFactory){
                  RedisTemplate<String,Object> redisTemplate=new RedisTemplate<>();
                  //key序列化
                  redisTemplate.setKeySerializer(new StringRedisSerializer());
                  //value序列化
                  redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
                  //hash類型key的序列化
                  redisTemplate.setHashKeySerializer(new StringRedisSerializer());
                  //hash類型value的序列化
                  redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
                  redisTemplate.setConnectionFactory(redisConnectionFactory);
                  return redisTemplate;
              }
          }
          

          ③ 優(yōu)化處理

              @Autowired
              private NewsService newsService;
              @Autowired
              private RedisTemplate redisTemplate;
              @Autowired
              private ThymeleafViewResolver viewResolver;
          
              @RequestMapping(value="/news",produces="text/html;charset=utf-8")
              @ResponseBody
              public String roles(Model model, @RequestParam(value="pageNo",defaultValue="1")Integer pageNo
                      , @RequestParam(value="pageSize",defaultValue="10")Integer pageSize
                      , HttpServletRequest request, HttpServletResponse response){
              //Redis中獲取頁面,如果不為空,則直接返回頁面
                  ValueOperations valueOperations=redisTemplate.opsForValue();
                  String html=(String) valueOperations.get("news-list");
                  if (!StringUtils.isEmpty(html)){
                      return html;
                  }
                  PageHelper.startPage(pageNo,pageSize);
                  List<News> list=newsService.list();
                  PageInfo<News> pageInfo=new PageInfo<>(list);
                  model.addAttribute("news",list);
                  model.addAttribute("pageInfo",pageInfo);
                 //如果為空,手動渲染,存入Redis中并返回
                  WebContext context=new WebContext(request, response, request.getServletContext(), request.getLocale(), model.asMap());
                  html=viewResolver.getTemplateEngine().process("news-list", context);
                  if (!StringUtils.isEmpty(html)){
                     //給緩存設(shè)置過期時間
                      valueOperations.set("news-list",html,60, TimeUnit.SECONDS);
                  }
                  return html;
              }
          

          ④ Redis查看

          6. 注意事項

          注意@Controller和@RestController的區(qū)別,本項目使用的是模板渲染頁面,而@Controller就是用來響應(yīng)頁面的;而@RestController是用來返回Json

          在項目優(yōu)化階段需要在方法上添加注解@ResponseBody,因為我們是將整個頁面進(jìn)行緩存 ,所以要將頁面轉(zhuǎn)換成JSON進(jìn)行存儲。

          注入Thymeleaf解析器,將具體的 頁面進(jìn)行解析成Json字符串進(jìn)行存儲

          將存入Redis中的數(shù)據(jù)加上過期時間,因為頁面中的數(shù)據(jù)要和數(shù)據(jù)庫保持一致,如果用戶看到是幾十秒之前或一分鐘之前的數(shù)據(jù)還是勉強(qiáng)可以接受的。

          目前代碼已經(jīng)同步到Gitee:

          https://gitee.com/gao-wumao/supplier


          來源:blog.csdn.net/Gaowumao?type=blog

          圖解析的實現(xiàn)基礎(chǔ)

          視圖解析器(ViewResolver)是 Spring MVC 的重要組成部分,負(fù)責(zé)將邏輯視圖名解析為具體的視圖對象。
          Spring MVC 提供了很多視圖解析類,其中每一項都對應(yīng)著 Java Web 應(yīng)用中特定的某些視圖技術(shù)。

          viewResolver組件會將viewName解析成view對象,view對象會調(diào)用render完成結(jié)果的處理。

          • ViewResolver 與 View 接?
            • AbstractCachingViewResolver
              • UrlBasedViewResolver
                • FreeMarkerViewResolver
                • InternalResourceViewResolver
              • ContentNegotiatingViewResolver 根據(jù)請求文件名或Accept頭解析視圖。

          一些可參閱的博客:

          http://c.biancheng.net/spring_mvc/view-resolver.html

          https://blog.csdn.net/fengyuhan123/article/details/79723310

          DispatcherServlet 中的視圖解析邏輯

          • initStrategies()
            • initViewResolvers() 初始化了對應(yīng) ViewResolver
          • doDispatch()
            • processDispatchResult()
            • 沒有返回視圖的話,嘗試 RequestToViewNameTranslator
            • resolveViewName() 解析 View 對象

          一些可參閱的博客:

          https://blog.csdn.net/u013541707/article/details/108511017

          使? @ResponseBody 的情況

          • 在 HandlerAdapter.handle() 的中完成了 Response 輸出
            • RequestMappingHandlerAdapter.invokeHandlerMethod()
              • HandlerMethodReturnValueHandlerComposite.handleReturnValue()
                • RequestResponseBodyMethodProcessor.handleReturnValue()

          轉(zhuǎn)發(fā)與重定向

          • redirect: 重定向
          • forward: 轉(zhuǎn)發(fā)

          Spring MVC 中的常?視圖

          Spring MVC ?持的視圖

          官方文檔:https://docs.spring.io/spring-framework/docs/5.1.5.RELEASE/spring-framework-reference/web.html#mvc-view

          ?持的視圖列表:

          • Jackson-based JSON / XML
          • Thymeleaf & FreeMarker

          配置 HttpMessageConverter

          在之前的RequestMapping的Handler也有提到過Converter,在視圖的部分也有自己對應(yīng)的HttpMessageConverter

          • 通過 WebMvcConfigurer 的 configureMessageConverters()
          • Spring Boot ?動查找 HttpMessageConverter 進(jìn)?注冊

          Spring Boot 對 Jackson 的?持

          • JacksonAutoConfiguration
            • Spring Boot 通過 @JsonComponent 注冊 JSON 序列化組件
            • Jackson2ObjectMapperBuilderCustomizer
          • JacksonHttpMessageConvertersConfiguration
            • 增加 jackson-dataformat-xml 以?持 XML 序列化

          Thymeleaf

          “Thymeleaf is a modern server-side Java template engine for both web and standalone environments.” – https://www.thymeleaf.org/

          • 添加 Thymeleaf 依賴
            • org.springframework.boot:spring-boot-starter-thymeleaf
          • Spring Boot 的?動配置
            • ThymeleafAutoConfiguration
            • ThymeleafViewResolver
          • Thymeleaf 的?些默認(rèn)配置
            • spring.thymeleaf.cache=true
            • spring.thymeleaf.check-template=true
            • spring.thymeleaf.check-template-location=true
            • spring.thymeleaf.enabled=true
            • spring.thymeleaf.encoding=UTF-8
            • spring.thymeleaf.mode=HTML
            • spring.thymeleaf.servlet.content-type=text/html
            • spring.thymeleaf.prefix=classpath:/templates/
            • spring.thymeleaf.suffix=.html

          主站蜘蛛池模板: 日本国产一区二区三区在线观看| 无码日韩精品一区二区三区免费| 变态拳头交视频一区二区| 国产精品无圣光一区二区| 久久精品一区二区三区AV| 精品少妇一区二区三区在线| 麻豆精品人妻一区二区三区蜜桃 | 国产精品一区二区香蕉| 欧洲精品一区二区三区| 日韩精品视频一区二区三区| 国产美女露脸口爆吞精一区二区| 国产精品视频一区二区三区无码| 在线观看中文字幕一区| 亚洲一区二区中文| 国产内射999视频一区| 日韩在线一区高清在线| 精品人妻AV一区二区三区| 国产一区玩具在线观看| 国产凸凹视频一区二区| 欧美成人aaa片一区国产精品| 成人无码AV一区二区| 亚洲国产AV一区二区三区四区| 国产免费私拍一区二区三区| 99精品国产高清一区二区| 国产午夜福利精品一区二区三区| 国产一区二区三区夜色| 精品女同一区二区| 亚洲国产一区二区a毛片| 日韩精品无码一区二区三区四区| 精品无码成人片一区二区98 | 99精品一区二区三区| 日本一区二区三区精品中文字幕| 熟女少妇丰满一区二区| 亚洲精品伦理熟女国产一区二区| 亚洲一区中文字幕久久| 日韩一区二区三区在线精品| 波多野结衣一区二区三区88| 国产一区二区三区在线观看免费| 免费一本色道久久一区| 中文字幕在线无码一区| 日本一区二区三区在线视频观看免费 |