Tổng quan về Kiến trúc Dự án và Quy trình Phát triển

1. Kiến trúc Dự án Truyền thống và Khung SSM

1.1. Lập trình Mạng

Chi tiết tại: https://www.cnblogs.com/szrs/p/12121032.html

1.2. Giới thiệu về Kiến trúc và Khung

  • Kiến trúc tổng thể phát triển phần mềm B/S (Browser/Server) và C/S (Client/Server) là kiến trúc ứng dụng đơn lẻ.
  • Kiến trúc hướng dịch vụ (SOA - Service-Oriented Architecture).
  • Các quyết định về kiến trúc được thể hiện qua khung và chương trình phần mềm được phát triển. MVC là một mẫu phát triển, nhiều khung dựa trên tư tưởng lập trình này, tách biệt xử lý giao diện người dùng, gọi chức năng và triển khai chức năng.

1.3. Quy trình Giới thiệu Khung

  • Cấu hình mybatis.xml.
  • Tích hợp web.xml, applicationContext.xml và mybatis.xml.
  • Tích hợp SpringMVC với mybatis.xml và applicationContext.xml: Ba tệp cấu hình chính là web.xml, springmvc.xml và applicationContext-mybatis.xml. Thông thường, hai tệp sau không được gộp chung.
  • Dự án SOA: Tách springmvc.xml thành nhiều tệp cấu hình. Bao gồm AOP, Dubbo, đọc tài nguyên tĩnh.

1.3.1. Bước 1: Thảo luận về Khung: Dự án B/S, Khung SSM

Dự án B/S hoạt động dựa trên máy chủ và trình duyệt web, về cơ bản là một kiến trúc ứng dụng đơn lẻ. Với lượng truy cập nhỏ, điểm kỹ thuật chính là các framework giúp tăng hiệu quả truy cập cơ sở dữ liệu: các framework truy cập dữ liệu (ORM) giúp đơn giản hóa công việc CRUD (Create, Read, Update, Delete). Ánh xạ quan hệ đối tượng-quan hệ (Object-Relational Mapping - ORM) là yếu tố then chốt. Chỉ cần một ứng dụng duy nhất, triển khai tất cả các chức năng cùng nhau để giảm chi phí và số lượng nút triển khai. Điều này không yêu cầu phát triển phân tán. Phát triển phân tán liên quan đến các framework dịch vụ, ví dụ như Dubbo: nhà cung cấp dịch vụ, trung tâm đăng ký và người tiêu dùng dịch vụ. So với việc triển khai dự án trên nhiều máy chủ Linux, chi phí thấp hơn nhiều. Phần dưới đây sẽ giải thích chi tiết về việc xây dựng dự án B/S và dự án phân tán.

1.3.2. Bước 2: Thảo luận về Thiết lập Môi trường Phát triển

Quy trình thiết lập môi trường phát triển: Đầu tiên, sử dụng khung SSM. Chúng ta sẽ thiết lập khung phát triển trước. Trước khi thiết lập khung, chúng ta cần nhập các tệp jar cần thiết vào dự án.

  • Jar cốt lõi.
  • Log4j: Gói nhật ký.
  • Asm: Gói xử lý tệp java, Spring và MyBatis phụ thuộc vào gói này để hoạt động.
  • Cglib: Gói proxy động của MyBatis. Với gói này, có thể khởi tạo các lớp triển khai của giao diện và thực thi các phương thức.
  • Commons: Gói ghi nhật ký của Spring.
  • Javaassist: Gói hỗ trợ tệp mã byte, chịu trách nhiệm xử lý tệp mã byte.
  • Log4j: Gói nhật ký cho chương trình java.
  • Mybatis-3.2.7.jar: Gói cốt lõi thực thi framework MyBatis.
  • Slf4j: Một định dạng gói nhật ký khác. Vì MyBatis hỗ trợ nhiều định dạng nhật ký, có thể lựa chọn khi chạy.

1.3.3. Bước 3: Thảo luận về Cấu trúc và Nguyên lý Tệp Cấu hình

1.3.3.1. Cấu hình Framework MyBatis
1. Tệp mybatis.xml trong thư mục src:

Đầu tiên, sửa đường dẫn trình xác thực tài liệu .dt thành cục bộ, trong xmlcatalog của xml trên Windows.

  • Thẻ gốc: configuration. Tất cả các thẻ khác được đặt bên trong thẻ này. settings để bật nhật ký log4j; typeAliases để đặt bí danh cho các gói.
  • environments: Môi trường sử dụng của framework MyBatis. Thuộc tính default phải giống với thuộc tính name của thẻ con environment bên trong nó.
  • datasource: Nguồn dữ liệu để kết nối cơ sở dữ liệu. Các thẻ con properties bao gồm: Driver, url, username, password. Chúng cũng có thể được cấu hình trong configuration hoặc được nhập từ bên ngoài. Sử dụng công nghệ connection pool.
  • transactionManager:
                    
                    <transactionManager type="JDBC"></transactionManager> 
                    <transactionManager type="MANAGED"></transactionManager> 
                
  • mappers: Nhập và tải bất kỳ tệp tài nguyên nào vào tệp cấu hình hiện tại.
                    <mappers>
                         
                        <mapper resource="com/bjsxt/mapper/FlowerMapper.xml"/> 
                        <mapper class="com.bjsxt.mapper.ClassroomMapper"/> 
                        <mapper class="com.bjsxt.mapper.StudentMapper"/>
                    </mappers>
                
    Các lớp như POJO (Plain Old Java Object) là các lớp thực thể. Mapper là các giao diện, chỉ viết các phương thức. Đối với các câu lệnh SQL phức tạp, nên viết bằng XML, ví dụ như SQL động, phân trang, truy vấn mờ. Xem lại các câu lệnh SQL truy vấn trong MyBatis 8 về trang bị tự động, trang bị thủ công và truy vấn N+1. --> Tương ứng giữa tham số và thuộc tính của câu lệnh truy vấn SQL.
2. Tệp mapper.xml:

        <mapper namespace="com.bjsxt.mapper.ClassroomMapper">
    

Kiểm thử: Bao gồm trường hợp chỉ có tệp mapper.xml và trường hợp có giao diện mapper. Đối với trường hợp đầu, sau khi lấy SqlSessionFactory từ đối tượng resources, sử dụng mẫu Builder SqlSessionFactoryBuilder() để nhanh chóng tạo một đối tượng khởi tạo. Sau đó, lấy đối tượng SqlSession được đóng gói với API cho tất cả các hoạt động CRUD (Create, Read, Update, Delete) trên cơ sở dữ liệu. Với đối tượng session, thực hiện các thao tác thêm, sửa, xóa, truy vấn. Khi có giao diện mapper, bạn cũng có thể lấy lớp proxy động của giao diện mapper để gọi các phương thức trong mapper.

        // Tải tệp cấu hình mybatis.xml hiện tại
        InputStream is = Resources.getResourceAsStream("mybatis.xml");
        // Xây dựng đối tượng nhà máy SqlSessionFactory bằng trình xây dựng
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        // Lấy đối tượng SqlSession
        SqlSession session = factory.openSession();
        FlowerMapper fm = session.getMapper(FlowerMapper.class);
        //int n = fm.insFlower("玫瑰", 12.23, "中国");
        Flower f = new Flower();
        f.setName("杜鹃");
        f.setPrice(12.3);
        f.setProduction("北京");
        // Thêm giống hoa mới
        int n = fm.insFlower2(f); // Hoặc:
        int n = session.insert("com.bjsxt.mapper.FlowerMapper.insFlower", f);
        System.out.println(n);
        session.commit();
        session.close();
    

Mở rộng bộ nhớ đệm của MyBatis: Sau khi kiểm thử xong, nhất định phải đóng session. Nếu là thao tác DML, cần phải commit giao dịch.

Bộ nhớ đệm MyBatis: Giảm thiểu tương tác với cơ sở dữ liệu, là một trung gian được thiết lập giữa cơ sở dữ liệu và ứng dụng.

  • Bộ nhớ đệm cấp 1: Dựa trên đối tượng sqlSession. Lưu trữ đối tượng PreparedStatement. Áp dụng cho các thẻ.
  • Bộ nhớ đệm cấp 2: Dựa trên SqlSessionFactory. Mỗi lần tạo một đối tượng sqlSession sẽ có bộ nhớ đệm. Hiệu quả cao hơn, nhưng có thể gây dư thừa dữ liệu, làm cho dữ liệu không chính xác. Để tránh việc tạo quá nhiều đối tượng POJO, thêm cấu hình sau vào tệp cấu hình mybatis.xml:
                    <cache readOnly="true"></cache>
                

Định danh dữ liệu: Giá trị id của thẻ truy vấn trong tệp ánh xạ.

  • Đối tượng ThreadLocal: Tương tự như một lớp chứa, lưu trữ một đối tượng (object), và có thể truy cập ở bất kỳ đâu trong cùng một luồng. Tạo một lớp tiện ích, sử dụng mẫu thiết kế Factory, để tất cả các session là một đối tượng duy nhất.
1.3.3.2. Cấu hình Spring
  1. Cấu hình Spring: Bước đầu tiên là nhập các gói cần thiết. Tạo tệp applicationContext.xml:
    • Schema mạnh mẽ hơn DTD, cung cấp trình xác thực, gợi ý và có thể mở rộng chức năng mới thông qua các thành phần mở rộng xác thực, có thể liên tục thích ứng với các thay đổi về nội dung và chức năng của tài liệu XML.
  2. Chỉ tệp cấu hình Spring: Chỉ cần khởi tạo và cấu hình thẻ bean với các thuộc tính idclass: hỗ trợ IOC (Inversion of Control - Điều khiển Ngược chiều) và DI (Dependency Injection - Tiêm Phụ thuộc).
  3. Spring không làm lại những thứ đã có. Sự ra đời của nó chủ yếu phục vụ lớp Service (tầng nghiệp vụ), không cần phải tự khởi tạo đối tượng.

    • IOC: Điều khiển Ngược chiều. Trước đây, đối tượng được khởi tạo bằng cách gọi new. Bây giờ, chỉ cần cấu hình bean trong tệp cấu hình cho đối tượng cần khởi tạo, và việc tạo đối tượng được giao cho Spring Container. Có ba cách: type, name, index.
    • DI: Tiêm Phụ thuộc. Ý nghĩa tương tự như IOC. Phụ thuộc là mối quan hệ giữa các lớp. Ở đây, sử dụng "liên kết" (association) sẽ phù hợp hơn, vì một lớp đóng vai trò là thuộc tính của lớp khác, và thuộc tính này được gán giá trị.
                      // Kiểm thử:
                      // Classpath: Tìm kiếm tệp cấu hình xml từ thư mục classes, tạo Spring Container
                      ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
                      // Lấy đối tượng People
                      People people = ac.getBean("peo", People.class);
                  
    • Về tiêm phụ thuộc: Có tiêm tự động: autowire. Các tùy chọn bao gồm byName, byType, constructor. Khi đặt là NO, giá trị của thuộc tính default-autowire sẽ được sử dụng để xác định. typename ở đây đề cập đến giá trị id của thẻ bean của lớp làm thuộc tính.

      Sau khi giới thiệu chú thích, khi tệp cấu hình bao gồm:

                      <context:component-scan base-package="com.bjsxt.service.impl"></context:component-scan>
                  
      Hỗ trợ quét chú thích cho lớp com.bjsxt.service.impl (được cho là đã đóng gói thuộc tính nameclass của bean). Khi hỗ trợ chú thích, @Autowired tiêm theo byName, chú thích @Resource lần lượt tiêm theo byNamebyType. Ngoài ra, Spring còn có các thẻ con khác. Chúng tôi chỉ giới thiệu cấu hình của nó để khởi tạo đối tượng, tức là cấu hình bean (và hỗ trợ chú thích).
    • Tiếp theo là Spring tích hợp MyBatis và các thẻ con khác (aop, tx, context): Tất cả các thẻ này đều yêu cầu nhập tệp mở rộng trình xác thực tài liệu mới.
    • 3.1. Spring tích hợp MyBatis
      • Hai cách tích hợp:
      • Cấu hình tệp web.xml: Sử dụng listener và đường dẫn để tự động tải tệp application.xml. Sử dụng <context-param><listener>.
      • Tệp applicationContext-mybatis.xml:
        • Cấu hình nguồn dữ liệu dataSource. context:property-placeholder cho phép nạp từ tệp cấu hình bên ngoài. Lưu ý rằng tên thuộc tính property không thể tùy ý đặt, phải tìm trong tệp nguồn.
        • Cấu hình đối tượng SqlSessionFactory, tức là để Spring quản lý instance của lớp factory MyBatis.
        • Cấu hình Spring để quản lý các giao diện trong gói mapper của MyBatis.
        • Cấu hình bean cho serviceImpl. Bước này thường có hỗ trợ chú thích, không cần thêm bean vào tệp cấu hình mỗi khi tạo một giao diện và lớp triển khai của nó. Chỉ cần cấu hình thẻ context:component-scan để cho phép quét chú thích cho lớp triển khai này. Thẻ này yêu cầu thêm tệp mở rộng context của trình xác thực tài liệu. Khi không sử dụng chú thích, sử dụng WebApplicationContext để lấy đối tượng bean đã được khởi tạo. Khi không khởi tạo bằng chú thích, cần có phương thức getter và setter cho lớp được sử dụng làm thuộc tính.
        • Sau khi tích hợp SpringMVC, tệp quét chú thích cho tầng controller thường được cấu hình riêng biệt với tệp quét chú thích cho tầng nghiệp vụ.

      Hiện tại đã hoàn tất cơ bản việc tích hợp Spring và MyBatis.

      Tất nhiên, Spring còn hỗ trợ các khía cạnh lập trình giao dịch tx và lập trình đối tượng khía cạnh aop. Chúng ta sẽ thảo luận chi tiết hơn khi triển khai chức năng dự án.

      3.2. AOP và TX
      • tx (Giao dịch):
        • Giao dịch bằng mã: Mã phải liên quan trực tiếp đến giao dịch, ví dụ như commit, rollback.
        • Giao dịch khai báo: Giao giao dịch cho Spring xử lý. Chỉ cần khai báo các phương thức cần thêm giao dịch. Liên quan đến AOP.

      Trong dự án SSM, giao dịch được thêm vào tầng nghiệp vụ, tức là tầng service. Các phương thức của tầng service được coi là điểm cắt (pointcut). Nếu có lỗi xảy ra, thông báo sẽ không nhận được giao dịch nếu xử lý lỗi ở tầng nghiệp vụ. Thêm cấu hình giao dịch vào tệp cấu hình:

      Trong applicationContext.xml:

      1. Thêm bean cho lớp đóng gói giao dịch. TransactionManager để Spring tải lớp xử lý giao dịch.
      2. Các phương thức cần xử lý giao dịch: thẻ tx.
                            <tx:advice id="tran" transaction-manager="transactionManager">
                                <tx:attributes>
                                    <tx:method name="register" read-only="false"/><!-- Giá trị mặc định là false, nghĩa là xử lý giao dịch. Nếu là true, nghĩa là không xử lý giao dịch, thường dùng cho các phương thức truy vấn. -->
                                </tx:attributes>
                            </tx:advice>
                        
      3. Thêm thông báo (advice): tức là AOP: aop:config -> aop:pointcut -> aop:advisor.

      Spring sử dụng proxy động của JDK ở tầng dưới. Theo mặc định, nó không tạo ra đối tượng thực thể thực sự của giao diện. Vấn đề phát sinh là: nếu muốn thực thi một phương thức của giao diện, nhất định phải tạo một đối tượng proxy động. Lúc này, nếu muốn chuyển đổi proxy động thành thực thể thực sự, chắc chắn sẽ ném ra lỗi chuyển đổi proxy động $proxy.

      Cách giải quyết:

      Trong tệp cấu hình Spring, thêm thẻ:

                  <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
              

      Ý nghĩa của thẻ này là chuyển đổi proxy động ở tầng dưới từ JDK sang CGLIB. Sau khi chuyển đổi, bất kể có chuyển đổi kiểu hay không, sẽ không còn lỗi nữa. Lưu ý: ngay cả khi sử dụng proxy động của JDK, nếu không xảy ra chuyển đổi, cũng sẽ không có lỗi.

      Giá trị của proxy-target-class: false là giá trị mặc định, nghĩa là không chuyển đổi thành thực thể. true thì ngược lại.

      Tính lan truyền giao dịch (Transaction Propagation): Hiểu biết: Trong các yêu cầu đặc biệt, một số phương thức có thể gọi lẫn nhau trong quá trình thực thi, liên quan đến nhiều giao dịch. Kiểm soát cách thức thực thi giao dịch chính là tính lan truyền giao dịch. Ít gặp.

      Mức cách ly giao dịch:

      • Đọc bẩn (Dirty Read): Giữa hai giao dịch: Một giao dịch sửa đổi dữ liệu trong cơ sở dữ liệu nhưng chưa commit. Giao dịch khác tình cờ đọc được dữ liệu này, dữ liệu này không chính xác, tức là xảy ra đọc bẩn.
      • Đọc không lặp lại (Non-repeatable Read): Hiện tượng xảy ra trong cùng một giao dịch: Tức là giữa lần đọc thứ nhất và lần đọc thứ hai một dữ liệu trong một giao dịch, có một giao dịch khác đã sửa đổi dữ liệu đó. Do đó, dữ liệu đọc được hai lần sẽ khác nhau, tức là xảy ra đọc không lặp lại.
      • Đọc ảo (Phantom Read): Xảy ra khi các giao dịch không thực thi độc lập. Ví dụ, một lần đọc và một lần chèn dữ liệu. Khi xảy ra đồng thời (tức là thực thi đồng thời), có thể không đọc được toàn bộ dữ liệu (dữ liệu được nhập chưa kịp đọc).
      3.3. Tích hợp Ba thành phần của Khung SSM:

      3.3.1. web.xml

      Sau khi cấu hình context-paramlistener của Spring để tìm kiếm application.xml, cấu hình servlet và servlet-mapping của SpringMVC. Thông qua mapping của URL, chặn tất cả các truy cập vào bộ điều phối (DispatcherServlet), tìm name, sau đó tìm servlet có tên tương ứng, rồi tìm class tương ứng của nó, tức là bộ điều phối. Cần cấu hình thuộc tính load-on-startup là 1 để khởi tạo chủ động bộ điều phối. Đồng thời, cấu hình thẻ init-param để chỉ định tệp SpringMVC.xml nằm trong thư mục src.

                  <servlet>
                     <servlet-name>springmvc</servlet-name>
                     <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
                     <init-param>
                         <param-name>ContextConfigLocation</param-name>
                         <param-value>classpath:springmvc.xml</param-value>
                     </init-param>
                     <load-on-startup>1</load-on-startup>
                  </servlet>
                  <servlet-mapping>
                     <servlet-name>springmvc</servlet-name>
                     <url-pattern>/*</url-pattern>
                  </servlet-mapping>
              

      3.3.2. applicationContext-mybatis.xml

      Tại đây, cấu hình quét chú thích, nguồn dữ liệu, factory SqlSessionFactory, và quản lý MyBatis. Thêm khía cạnh AOP và giao dịch TX theo nhu cầu.

      Sau khi cấu hình url-pattern từ *.do thành /*, việc viết RequestMapping trở nên đơn giản hơn. Tuy nhiên, nó cũng chặn các tài nguyên tĩnh của yêu cầu. Khi trả về máy khách và yêu cầu lại, đường dẫn đã thay đổi. Lúc này, cần cấu hình tài nguyên tĩnh trong SpringMVC.xml.

      (1)

                  <beans xmlns="http://www.springframework.org/schema/beans"
                         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                         xmlns:context="http://www.springframework.org/schema/context"
                         xmlns:aop="http://www.springframework.org/schema/aop"
                         xmlns:tx="http://www.springframework.org/schema/tx"
                         xsi:schemaLocation="http://www.springframework.org/schema/beans
                                             http://www.springframework.org/schema/beans/spring-beans.xsd
                                             http://www.springframework.org/schema/context
                                             http://www.springframework.org/schema/context/spring-context.xsd
                                             http://www.springframework.org/schema/aop
                                             http://www.springframework.org/schema/aop/spring-aop.xsd
                                             http://www.springframework.org/schema/tx
                                             http://www.springframework.org/schema/tx/spring-tx.xsd">
      
                      <!-- Lưu ý: Trong tệp cấu hình Spring, chỉ quét tầng service, không quét tầng controller -->
                      <context:component-scan base-package="com.bjsxt.service.impl"/>
                      <context:property-placeholder location="classpath:db.properties"/>
      
                      <!-- Cấu hình nguồn dữ liệu -->
                      <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
                          <property name="driverClassName" value="${jdbc.driver}"/>
                          <property name="url" value="${jdbc.url}"/>
                          <property name="username" value="${jdbc.username}"/>
                          <property name="password" value="${jdbc.password}"/>
                      </bean>
      
                      <!-- Cấu hình factory SqlSessionFactory -->
                      <bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
                          <property name="dataSource" ref="dataSource" />
                          <!-- Cấu hình mapperLocations để chỉ định vị trí các tệp Mapper XML -->
                          <property name="mapperLocations" value="classpath:com/bjsxt/mapper/*.xml"/>
                      </bean>
      
                      <!-- Spring quản lý MyBatis -->
                      <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
                          <property name="basePackage" value="com.bjsxt.mapper"/>
                          <property name="sqlSessionFactoryBeanName" value="factory"/>
                      </bean>
      
                      
                      
                      <bean id="addRoleMenuAdvice" class="com.bjsxt.advice.AddRoleMenuAdvice"/>
                      
                      
                      <bean id="delRoleMenuAdvice" class="com.bjsxt.advice.DelRoleMenuAdvice"/>
      
                      <aop:config>
                          
                          <aop:pointcut expression="execution(* com.bjsxt.service.impl.RolesServiceImpl.addRoles(..))" id="pointcutAddRoleMenu"/>
                          <aop:pointcut expression="execution(* com.bjsxt.service.impl.RolesServiceImpl.delRole(..))" id="pointcutDelRoleMenu"/>
                          
                          <aop:advisor advice-ref="addRoleMenuAdvice" pointcut-ref="pointcutAddRoleMenu"/>
                          <aop:advisor advice-ref="delRoleMenuAdvice" pointcut-ref="pointcutDelRoleMenu"/>
                      </aop:config>
      
                      
                      <bean id="logsAdvice" class="com.bjsxt.advice.LogsAdvice"/> 
                      <bean id="loginLogsAdvice" class="com.bjsxt.advice.LoginLogsAdvice"/> 
                      <bean id="addCustomerAdvice" class="com.bjsxt.advice.AddCustomerAdvice"/> 
                      <bean id="delCustomerAdvice" class="com.bjsxt.advice.DelCustomerAdvice"/> 
      
                      <!-- <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> -->
                      <aop:config>                    
                          
                          <aop:pointcut expression="execution(* com.bjsxt.service.impl.CustomersServiceImpl.selectById(..))"id="pointcut2"/>
                          <aop:pointcut expression="execution(* com.bjsxt.service.impl.CustomersServiceImpl.addCustomer(..))"id="pointcut3"/>
                          <aop:pointcut expression="execution(* com.bjsxt.service.impl.CustomersServiceImpl.deleteCustomer(..))" id="pointcut4"/>
                          
                          <aop:advisor advice-ref="loginLogsAdvice" pointcut-ref="pointcut2"/>
                          <aop:advisor advice-ref="addCustomerAdvice" pointcut-ref="pointcut3"/>
                          <aop:advisor advice-ref="delCustomerAdvice" pointcut-ref="pointcut4"/>
                      </aop:config>
      
                  </beans>
              

      (2)

                  <!-- Cấu hình lập trình đối tượng khía cạnh, thông báo sau -->
                  
                  <bean id="addRoleMenuAdvice" class="com.bjsxt.advice.AddRoleMenuAdvice"/>
                  
                  
                  <bean id="delRoleMenuAdvice" class="com.bjsxt.advice.DelRoleMenuAdvice"/>
      
                  <aop:config>
                      
                      <aop:pointcut expression="execution(* com.bjsxt.service.impl.RolesServiceImpl.addRoles(..))" id="mypoint"/>
                      <aop:pointcut expression="execution(* com.bjsxt.service.impl.RolesServiceImpl.delRole(..))" id="mypointDelRM"/>
                      
                      <aop:advisor advice-ref="addRoleMenuAdvice" pointcut-ref="mypoint"/>
                      <aop:advisor advice-ref="delRoleMenuAdvice" pointcut-ref="mypointDelRM"/>
                  </aop:config>
                  
                  <bean id="logsAdvice" class="com.bjsxt.advice.LogsAdvice"/>
                  <bean id="loginlogsAdvice" class="com.bjsxt.advice.LoginlogsAdvice"/>
                  <bean id="addCusAdvice" class="com.bjsxt.advice.AddCusAdvice"/>
                  <bean id="delCusAdvice" class="com.bjsxt.advice.DelCusAdvice"/>
      
                  
                  <aop:config>                    
                      
                      <aop:pointcut expression="execution(* com.bjsxt.service.impl.CustomersServiceImpl.selById(..))"id="mypoint2"/>
                      <aop:pointcut expression="execution(* com.bjsxt.service.impl.CustomersServiceImpl.addCus(..))"id="mypoint3"/>
                      <aop:pointcut expression="execution(*com.bjsxt.service.impl.CustomersServiceImpl.delCus(..))" id="mypoint4"/>
                      
                      <aop:advisor advice-ref="loginlogsAdvice" pointcut-ref="mypoint2"/>
                      <aop:advisor advice-ref="addCusAdvice" pointcut-ref="mypoint3"/>
                      <aop:advisor advice-ref="delCusAdvice" pointcut-ref="mypoint4"/>
                  </aop:config>
              

      3.3.3. springmvc.xml

      Cấu hình thẻ quét chú thích cho controller và mvc driver để hỗ trợ quét chú thích.

      Khi truy cập tài nguyên tĩnh của trang web, cần cấu hình mvc:resources.

      Về cơ bản, cấu hình cơ bản bao gồm quét chú thích, driver hỗ trợ quét chú thích và cấu hình truy cập tài nguyên tĩnh.

                  <!-- Cấu hình truy cập tài nguyên tĩnh -->
                  <mvc:resources location="/" mapping="/**"/>
              

      Ba cấu hình còn lại được cấu hình theo nhu cầu.

      Trình phân giải tùy chỉnh:
                  <!-- Cấu hình trình phân giải tùy chỉnh -->
                  <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                      <property name="prefix" value="/"/>
                      <property name="suffix" value=".jsp"/>
                  </bean><br><br>
              
      Bộ lọc (Filter):

      Ví dụ: Xử lý lỗi mã hóa tiếng Trung. SpringMVC đã đóng gói sẵn lớp bộ lọc. Chỉ cần cấu hình trong web.xml.

      Giá trị của param-name không thể tùy ý đặt.

                  <init-param>
                      <param-name>encoding</param-name>
                      <param-value>utf-8</param-value>
                  </init-param>
              
      Trình chặn (Interceptor):
      1. Định nghĩa: Thực thi trước khi trình điều khiển được truy cập bởi máy khách, và thực thi lại sau khi trình điều khiển và JSP đã thực thi. Thực hiện một số công việc trước khi truy cập trình điều khiển, và thực hiện một số công việc sau khi truy cập trình điều khiển.
      2. Dựa trên đặc điểm: Tương tự như filter, tương tự như aop.
      3. So sánh trình chặn và bộ lọc:
        • filter: Có thể lọc tất cả các tài nguyên truy cập.
        • interceptor: Chỉ có hiệu lực đối với các phương thức của trình điều khiển.
      4. So sánh trình chặn và AOP:
        • aop: Liên kết thông báo (trước, sau) với tất cả các phương thức điểm cắt.
        • interceptor: Chỉ có hiệu lực đối với các phương thức của trình điều khiển.
      5. Nguyên lý thực thi: Việc triển khai trình chặn trước tiên cần triển khai giao diện HandlerInterceptor và thực hiện các phương thức liên quan.
      6. Thứ tự thực thi:
        • MyInterceptor.preHandle(): Thực thi trước trình điều khiển.
        • DemoController.demo1(): Thực thi trình điều khiển.
        • MyInterceptor.postHandle(): Sau trình điều khiển, trước JSP.
        • MyInterceptor.afterCompletion(): Sau JSP.
      7. Tham số trong phương thức:
        • req: Đối tượng yêu cầu.
        • resp: Đối tượng phản hồi.
        • Object: handler (phương thức trình điều khiển bị chặn).
                  <!-- Cấu hình trình chặn -->
                  <!-- Cách 1: Áp dụng cho tất cả các phương thức -->
                  
                  
                  
                  
                  <mvc:interceptors>
                      <bean id="myInterceptor" class="com.bjsxt.interceptor.MyInterceptor"/>
                      <bean id="myInterceptor2" class="com.bjsxt.interceptor.MyInterceptor2"/>
                  </mvc:interceptors>
                  
                  <context:component-scan base-package="com.bjsxt.controller"/>
                  
                  <mvc:annotation-driven/>
                  
                  <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                      <property name="prefix" value="/"/>
                      <property name="suffix" value=".jsp"/>
                  </bean>
                  
                  <mvc:resources location="/" mapping="/**"/>
                  
                  
                  
                  
                  <mvc:interceptors>
                      <mvc:interceptor>
                          <mvc:mapping path="/demo1"/>
                          <bean id="myInterceptor" class="com.bjsxt.interceptor.MyInterceptor"/>
                      </mvc:interceptor>
                      <mvc:interceptor>
                          <mvc:mapping path="/demo2"/>
                          <bean id="myInterceptor2" class="com.bjsxt.interceptor.MyInterceptor"/>
                      </mvc:interceptor> 
                  </mvc:interceptors>
              

      1.3.4. Bước 4: Logic Nghiệp vụ và Triển khai

      1.3.4.1. Ghi nhật ký AOP

      Các công nghệ được sử dụng trong triển khai, cài đặt, cấu hình và sử dụng: ghi nhật ký nghiệp vụ: ghi nhật ký tùy chỉnh, triển khai bằng chú thích.

      1. Tạo chú thích mới @interface, viết phương thức, giá trị mặc định là " ".
      2. Thêm hỗ trợ trong tệp cấu hình springmvc.xml.
                        <!-- Kích hoạt hỗ trợ chú thích @AspectJ -->
                        <aop:aspectj-autoproxy proxy-target-class="true" />
                        <!-- Khía cạnh -->
                        <bean id="systemLogAspect" class="org.rentcar.annotation.SystemLogAspect"/>
                    
        Phương thức khía cạnh này sẽ ghi lại những gì cần thiết vào cơ sở dữ liệu.
      3. Tạo phương thức khía cạnh và sử dụng nguyên lý phản chiếu để lấy nội dung chú thích tùy chỉnh đã được chú thích ở tầng Controller.

      Định nghĩa điểm cắt ở đây:

              @Pointcut("execution (* org.rentcar.controller.*.*(..))")
              public void controllerAspect() {
              }
      
              /**
               * Thông báo sau khi thực thi, dùng để chặn tầng Controller ghi lại thao tác của người dùng
               * @param joinPoint Điểm cắt
               * joinPoint có thể lấy danh sách tham số của điểm kết nối, đối tượng phương thức, đối tượng mục tiêu, bản thân đối tượng proxy.
               */
              @After("controllerAspect()")
              public void doAfter(JoinPoint joinPoint) {
                  HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
                  HttpSession session = request.getSession();
                  // Đọc người dùng từ session // Sẽ triển khai sau
                  User user = (User) session.getAttribute("user");
      
                  // IP yêu cầu
                  String ip = request.getRemoteAddr();
      
                  // Lấy mô tả phương thức của tầng controller
                  public static String getServiceMethodDescription(JoinPoint joinPoint) throws Exception {
                      String targetName = joinPoint.getTarget().getClass().getName();
                      String methodName = joinPoint.getSignature().getName();
                      Object[] arguments = joinPoint.getArgs();
                      Class targetClass = Class.forName(targetName);
                      Method[] methods = targetClass.getMethods();
                      String description = "";
                      for (Method method : methods) {
                          if (method.getName().equals(methodName)) {
                              Class[] parameterTypes = method.getParameterTypes();
                              if (parameterTypes.length == arguments.length) {
                                  description = method.getAnnotation(SystemLog.class).description();
                                  break;
                              }
                          }
                      }
                      return description;
                  }
              }
          

      1.3.4.2. Quyền truy cập RBAC (Role-Based Access Control)

      Ý tưởng: Liên quan đến trình chặn. Khi truy cập, trước tiên đi vào trình chặn. Ba bước kiểm tra:

      1. Kiểm tra xem đường dẫn có phải là phương thức đăng nhập trong trình điều khiển hay không: Nếu đúng, cho phép đi tiếp; nếu không, chuyển hướng đến trang đăng nhập.
      2. Kiểm tra xem người dùng có rỗng hay không. Nếu rỗng, chuyển hướng đến trang đăng nhập; nếu không, tiếp tục.
      3. Kiểm tra xem đối tượng user có chứa đường dẫn cần truy cập hay không. Nếu có, chuyển hướng; nếu không, chuyển hướng đến trang đăng nhập. (Ở đây, đối tượng thực thể user được đóng gói với một tập hợp các đường dẫn mà người dùng đó có quyền truy cập).
              String uri = req.getRequestURI(); // Ví dụ: /sxt/login
          

      Hai điểm khó hiểu nhất của RBAC: RBAC đơn giản nhất dựa trên URL cũng cần sáu bảng, ngoài ra còn có user, role, url, menu.

      • Thiết kế bảng cơ sở dữ liệu: Giới thiệu bảng role.
        1. Thiết kế role-user: Phân bổ vai trò trực tiếp cho người dùng, đơn giản, dễ thao tác.
        2. Thiết kế role-url: Phân bổ đường dẫn cho vai trò. Để đảm bảo an toàn truy cập, kiểm tra trong trình chặn để ngăn chặn người dùng chưa đăng nhập truy cập trang của chương trình.
        3. Thiết kế role-menu: Chỉ định menu tương ứng cho từng vai trò.
        Sau khi tạo vai trò, phân bổ đường dẫn và menu cho vai trò, chỉ cần phân bổ vai trò cho người dùng.
      • Câu lệnh SQL: Chủ yếu là truy vấn đệ quy của bảng menu. Số hiệu cha của menu con chính là số hiệu cha của menu cha.

      Truy vấn đệ quy của menu menu: Sử dụng đệ quy trong mã. Tạo lớp thực thể userMenu với bốn thuộc tính: id, name, pid (id của nút cha), List<userMenu> children.

              List<UserMenu> list = menuMapper.showMenu(rid, pid);
              // System.out.println(list.get(0));
              for (UserMenu userMenu : list) {
                  List<UserMenu> menu = menuMapper.showMenu(rid, userMenu.getId());
                  userMenu.setChildren(menu);
              }
              return list;
          

      Trong đó, rid là id của vai trò, pid là id của nút cha trong menu.

              select * from menu where id in (select mid from role_menu where rid=#{0}) and pid=#{1}
          

      Mối quan hệ nhiều-nhiều giữa bảng vai trò và bảng menu: Khi truy vấn, trước tiên theo id vai trò để lấy ra id menu tương ứng của vai trò đó, sau đó theo id menu và pid để lấy ra tất cả các menu cha hiện tại, sau đó sử dụng vòng lặp để lấy ra các menu con của mỗi menu cha (là một tập hợp), sau đó sử dụng đệ quy để truy vấn các menu con của mỗi menu con.

      Thông thường có hai cấp độ thư mục.

      Vai trò thực tế của RBAC trong dự án:

      • Cho phép người dùng khác nhau xem các menu khác nhau (sau khi đăng nhập).
      • Hiệu ứng hiển thị trang web khác nhau cho người dùng khác nhau:
        • Một số người có thể thấy nút chức năng thêm.
        • Một số người chỉ có thể thấy nút chức năng hiển thị.
      • Những người khác nhau thực hiện các chức năng khác nhau dưới cùng một dự án.

      2. Dự án Phân tán và Các Công nghệ Liên quan

      • Kiến trúc ứng dụng đơn lẻ: Tăng hiệu quả của framework ORM ở tầng truy cập dữ liệu. Quá trình lưu trữ dữ liệu.
      • Kiến trúc ứng dụng theo chiều dọc: Khi lượng truy cập tăng dần, việc tăng máy cho một ứng dụng đơn lẻ mang lại hiệu quả ngày càng ít. Chia ứng dụng thành các ứng dụng độc lập không liên quan để tăng hiệu quả. Lúc này, framework Web (MVC) để tăng tốc phát triển trang front-end là yếu tố then chốt.
      • Kiến trúc dịch vụ phân tán: Khi số lượng ứng dụng theo chiều dọc ngày càng tăng, tương tác giữa các ứng dụng là không thể tránh khỏi. Trích xuất các nghiệp vụ cốt lõi làm dịch vụ độc lập, dần dần hình thành một trung tâm dịch vụ ổn định, giúp ứng dụng front-end phản ứng nhanh hơn với nhu cầu thị trường thay đổi. Lúc này, framework dịch vụ phân tán (RPC) để tăng cường tái sử dụng và tích hợp nghiệp vụ là yếu tố then chốt.
      • Kiến trúc điện toán lưu động: Khi số lượng dịch vụ ngày càng tăng, các vấn đề như đánh giá dung lượng và lãng phí tài nguyên dịch vụ nhỏ dần xuất hiện. Lúc này, cần thêm một trung tâm điều phối dựa trên áp lực truy cập để quản lý dung lượng của cụm theo thời gian thực, tăng hiệu quả sử dụng cụm. Lúc này, trung tâm quản lý và điều phối tài nguyên (SOA) để tăng hiệu quả sử dụng máy móc là yếu tố then chốt. Cân bằng tải Nginx, gọi máy chủ có áp lực thấp trong cụm.

      2.1. Quy trình Giải thích Dự án Thương mại Điện tử

      2.1.1. Xây dựng Dự án

      Kiến trúc hướng dịch vụ (SOA - Service-Oriented Architecture). Có quá nhiều dịch vụ, chia các dịch vụ cụ thể thành nhiều dự án. Các dự án dịch vụ được chia này được triển khai trên nhiều máy chủ, tổng thể chia thành hai module lớn là front-end và back-end.

      Quản lý dự án bằng Maven. Framework front-end là Easy-UI.

      Tạo ego-parent.

      Số lượng bảng trong thiết kế cơ sở dữ liệu không phải do tôi tham gia thiết kế.

      Tạo ego-pojo bằng kỹ thuật tạo mã ngược (reverse engineering).

      Trong quá trình viết, tạo module ego-commons để đặt các lớp chung.

      Chúng tôi sử dụng phát triển phân tán Dubbo. Tạo ego-service để viết giao diện dịch vụ. Tạo ego-dubbo để viết lớp triển khai dịch vụ và xuất bản dịch vụ lên trung tâm đăng ký.

      Các module còn lại như ego-manager, ego-portal, v.v. đều là người tiêu dùng dịch vụ.

      Phát triển phân tán của dự án ego:

      Ở đâu thể hiện phát triển phân tán? Ở đâu thể hiện tư tưởng SOA?

      Trả lời: SOA chia toàn bộ dự án thành nhiều module theo yêu cầu chức năng cụ thể, xuất bản dịch vụ trên một máy chủ riêng biệt, thể hiện tư tưởng kiến trúc hướng dịch vụ của SOA. Còn việc triển khai dự án, tức là người tiêu dùng dịch vụ, trên các máy chủ khác nhau, rõ ràng là Dubbo đang quản lý dịch vụ, thể hiện tư tưởng phát triển phân tán. Dự án có thể được triển khai trên nhiều máy chủ, nhưng các dự án này yêu cầu giống hệt nhau. Lúc này, cần sử dụng Nginx để proxy máy chủ, cân bằng tải, để tăng hiệu quả truy cập và giảm áp lực cho máy chủ. Điều này thể hiện cụm.

      Cân bằng tải Nginx: Mở cổng 80. Trong thư mục cài đặt Nginx /conf/nginx.conf, cấu hình ba phần liên tiếp:

      upstream trong thẻ server{} server {
      listen 80;
      server_name test.ego.com;
      location / {
      proxy_pass http://test.ego.com;
      }
      }
      upstream test.ego.com {
      server 192.168.26.10 weight=2;
      server 192.168.26.128 weight=3;
      server 192.168.26.138 weight=2;
      ...
      }

      server_name phải giống với tên trong upstream. proxy_pass là đường dẫn truy cập, upstream là đường dẫn proxy.

      Trong C:\Windows\System32\drivers\etc\hosts, cấu hình ánh xạ IP và tên miền.

      Lần đầu tiên thực hiện cân bằng tải, cần thay đổi biến môi trường của Windows.

      192.168.26.148 test.ego.com: Phần trước là IP của Nginx, phần sau là đường dẫn truy cập.

      Xây dựng dự án bằng Maven: Thêm phụ thuộc vào pom.xml.

      Nhà cung cấp dịch vụ: Người tiêu dùng dịch vụ:
      ego-parent
      ego-service
      ego-dubbo
      ego-pojo
      ego-commons
      ego-manager --> Quản lý back-end ---- 8080
      pom.xml
      ego-item --> Lưu trữ thông tin sản phẩm ---- 8081 -- Lưu trữ thông tin chi tiết sản phẩm vào Redis
      ego-portal --> Trang front-end ---- 8082
      ego-search --> Tìm kiếm sản phẩm - Solr --- 8083 -- Xây dựng Solr, lưu trữ thông tin sản phẩm vào Solr
      ego-passport -- Đăng nhập một lần ------ 8084
      ego-cart ---- Giỏ hàng --- 8085 -- Lưu trữ thông tin giỏ hàng vào Redis
      ego-order --- Đơn hàng ---- 8086
      ego-pay --> Trực tiếp viết vào ego-order

      2.1.2. Chức năng Cụ thể - Triển khai Module Giỏ hàng

      Tôi chủ yếu phụ trách module giỏ hàng, đồng thời cũng có hiểu biết nhất định về các module khác.

      Triển khai giỏ hàng:

      Cách triển khai:


        1. Thêm, xóa, sửa giỏ hàng.
        Khi bạn tìm kiếm và xem chi tiết sản phẩm, sẽ có một nút "Thêm vào giỏ hàng", không có nút thanh toán trực tiếp, giống như JD.com, bạn nhấp vào "Thêm vào giỏ hàng". Khi nhấp vào "Thêm vào giỏ hàng", thông tin sản phẩm đã được đóng gói thành một đối tượng thực thể giỏ hàng. Lưu trữ vào Redis. Vậy tại sao lại lưu trữ vào Redis? Đầu tiên, các thao tác như thêm, xóa cần tương tác liên tục với cơ sở dữ liệu. Bằng cách lưu trữ vào bộ nhớ đệm Redis, hiệu quả tương tác dữ liệu với cơ sở dữ liệu được tăng lên, cải thiện trải nghiệm người dùng. Tuy nhiên, quan trọng nhất là khi khách hàng mở giỏ hàng lần sau, các sản phẩm đã thêm trước đó vẫn còn tồn tại. Chúng ta đều đã từng mua sắm trên Taobao, JD.com. Giỏ hàng của bạn khi mở ra lần sau, các sản phẩm đó vẫn còn. Trước đây, khi làm hệ thống quản lý, nó là một cổng duy nhất, không vượt qua các dịch vụ. Chúng ta thường lưu trữ dữ liệu vào application, session hoặc cookie, nhưng rõ ràng là không hợp lý.
      1. Quy trình thêm: Chúng ta đều biết Redis là cơ sở dữ liệu phi quan hệ, lưu trữ dữ liệu theo cặp key-value. Ở đây, key được sử dụng là id của người dùng. Đầu tiên, trong phần đăng nhập một lần, chúng ta đã lưu trữ thông tin người dùng vào Redis, và id của nó là user:UUID. UUID này được lưu trữ trong cookie (trong lớp tiện ích chung ego-commons, đặt các công cụ cần thiết cho nhiều dịch vụ). Bằng cách này, chúng ta có thể lấy key của người dùng hiện tại được lưu trữ trong Redis, từ đó lấy thông tin người dùng. Thông qua thông tin người dùng, lấy id của người dùng, sau đó lấy key lưu trữ giỏ hàng. Sau đó, lấy thông tin sản phẩm thông qua itemId được truyền từ front-end (chúng ta đã lưu trữ thông tin sản phẩm vào Redis khi truy vấn chi tiết sản phẩm). Đóng gói thuộc tính cần thiết của giỏ hàng vào đối tượng thực thể giỏ hàng. Lưu ý ở đây là Redis có thể lưu trữ thông tin của nhiều sản phẩm, vì vậy phần đọc từ giỏ hàng ra là một tập hợp các sản phẩm trong giỏ hàng.
      2. Hiển thị thông tin giỏ hàng: Sau khi thêm giỏ hàng, chúng ta xin nhắc lại rằng trên trang giỏ hàng, không có nút thanh toán. Lúc này, chỉ có thể nhấp vào "Đi thanh toán", sẽ nhảy đến một dịch vụ thanh toán? 666, viết đến đây đã mệt.

      2.1.3. Đăng nhập một lần (Single Sign-On - SSO)

      Trong dự án phân tán, vì có các máy chủ khác nhau, cần có SSO. Thông tin người dùng được lưu trữ trong Redis. Thêm trình chặn. Khi truy cập mà chưa đăng nhập, sẽ trực tiếp chuyển hướng đến trang đăng nhập. Ý tưởng triển khai: key = user:UUID, UUID được lưu trữ trong cookie và truyền về back-end để kiểm tra. Thêm: so sánh người dùng được truyền từ front-end với cơ sở dữ liệu. Nếu tồn tại, tạo UUID, lưu trữ thông tin người dùng vào Redis, đồng thời chuyển hướng đến trang trước đó.

      Tại sao cần làm vậy? Nhiều dịch vụ, truy cập khác domain. Thông tin người dùng được lưu trữ trong Redis. Trên các trang dịch vụ khác, thêm trình chặn. Nếu người dùng chưa đăng nhập, sẽ chuyển hướng đến trang đăng nhập.

      Lưu ý: Việc lưu trữ trong Redis yêu cầu sử dụng JedisPool và lớp triển khai của nó để thực hiện các thao tác set, get, exist trên Redis. Đồng thời, thêm các lớp tiện ích cookie và json vào ego-common.

      2.1.4. Ôn tập Cài đặt Các Thành phần Trung gian Phổ biến

      2.1.4.1. vsftp - Proxy Nginx

      Giao thức FTP: Giao thức truyền tệp văn bản. An toàn hơn, hiệu quả tải lên tệp nhanh hơn, tải lên nhiều tệp cùng lúc, chỉ định người dùng, chỉ có thể thấy nội dung của đường dẫn được chỉ định. Sử dụng giao thức TCP/IP. Nhược điểm là cần cài đặt máy chủ FTP, tệp trên máy chủ FTP cần được tải xuống mới có thể sử dụng. So với giao thức truyền siêu văn bản HTTP, giao thức HTTP là giao thức mạng được sử dụng phổ biến nhất trên Internet. Vsftp có thể coi là một thành phần nhỏ của Linux.

      Tại sao sử dụng máy chủ FTP làm máy chủ hình ảnh?

      Quản lý thống nhất tài nguyên tệp trong dự án phân tán. Đảm bảo đường dẫn là duy nhất!

      Sử dụng kỹ thuật Java FTPClient để tải ảnh lên máy chủ vsftp. Cần thêm phụ thuộc vào pom.xml.

      Vsftpd được truy cập qua giao thức FTP! Cổng của giao thức FTP là 21. FileZilla: sftp: cổng mặc định là 22.

      Cài đặt: Đồng thời sử dụng Nginx để proxy truy cập Vsftp, sử dụng HTTP để truy cập.

      Cài đặt dễ dàng:

              [root@bogon ~]# yum -y install vsftpd
              -y: nghĩa là yes
          

      Sau khi cài đặt, có tệp /etc/vsftpd/vsftpd.conf là tệp cấu hình của vsftpd.

      /etc/vsftpd/vsftpd.conf: tắt truy cập ẩn danh.

      Khởi động lại dịch vụ ftp: service vsftpd restart

      Truy cập: ftp://192.168.26.30/gaoyy.jpg

      Proxy bằng Nginx: Proxy tiến (Forward Proxy): Proxy một đường dẫn, truy cập một máy chủ, do máy khách quyết định. Ví dụ: Nginx proxy máy chủ ảnh vsftp.

      Proxy ngược (Reverse Proxy): Proxy một máy chủ khác, và máy chủ này không do máy khách quyết định. Ví dụ: Cảnh sát mạng, cân bằng tải trong dự án thương mại điện tử.

      Được viết bằng C: Cần cài đặt môi trường gcc: yum install gcc-c++ -y

      Cấu hình trong tệp cấu hình nginx.conf. Khi proxy vsftp: đặt người dùng quyền truy cập, sửa đổi đường dẫn location.

      Sau khi sửa đổi tệp cấu hình, cần phải khởi động lại.

      2.1.4.2. redis Cluster, Quản lý Cluster bằng Ruby

      Cơ sở dữ liệu phi quan hệ, viết bằng C, lưu trữ dữ liệu theo cặp key-value, không cần định nghĩa trước từ điển lưu trữ dữ liệu, lưu trữ trong bộ nhớ, truy cập nhanh. Bộ nhớ đệm --> Có cơ chế lưu trữ bền vững: AOF và RDB.

      • AOF: Sao lưu thời gian thực, liên tục ghi nhật ký vào tệp nhật ký. Dẫn đến tệp quá lớn, thời gian phục hồi dài.
      • RDB: Sao lưu sau một khoảng thời gian nhất định, dẫn đến mất dữ liệu nhiều. Phương thức mặc định.

      RedisDesktopManager để quản lý cơ sở dữ liệu Redis.

      Cài đặt:

      • Cài đặt độc lập: Sao chép gói nén Redis vào thư mục root và giải nén --> Thêm phụ thuộc gcc-c++: yum install gcc-c++ automake autoconf --> Tạo thư mục cài đặt mkdir -p /usr/local/redis, và biên dịch bằng make.
      • Cài đặt: make install PREFIX=/usr/local/redis
      • Sao chép tệp cấu hình redis.conf vào thư mục bin và sửa đổi daemonize trong tệp cấu hình redis.conf thành yes để khởi động ở chế độ nền.
      • Sau đó, chạy ./redis-server ./redis.conf để khởi động lại dịch vụ.
      • Kết nối máy khách với dịch vụ, cần cài đặt cổng tường lửa hoặc tắt tường lửa trực tiếp.
      • Và đặt địa chỉ IP: Cấu hình bind trong redis.conf thành: bind *. Số lượng cơ sở dữ liệu databases 16 nghĩa là có 16 cơ sở dữ liệu mặc định.
      • redis-cli: nghĩa là client Redis.
      • redis-server: nghĩa là server Redis.
      • Năm loại dữ liệu: String, Hash, List, Set, Sorted Set.
      • Trong phát triển thực tế, thường sử dụng String và Hash { "key1": "value1", "key2": "value2" } theo cặp key-value.
      • Trong Eclipse, để quản lý cơ sở dữ liệu Redis, trước tiên cần nhập gói jar, sử dụng JedisPool để quản lý nguồn dữ liệu.

      Triển khai và quản lý Cluster:

      Trong thực tế, thường sử dụng Redis cluster để lưu trữ dữ liệu. Cài đặt Redis cluster và quản lý Redis cluster bằng Ruby.

      Cluster độc lập:

      1. Sao chép script Ruby vào thư mục root, giải nén, và tạo thư mục cấu hình, nhật ký và dữ liệu Redis trong thư mục root.
      2. Sao chép sáu tệp cấu hình Redis và một tệp cấu hình chung (chỉ cần sửa đổi bind (IP) và hỗ trợ cluster, do đó cần một tệp cấu hình chung) vào thư mục cấu hình đã tạo. Sau đó tạo ./start.sh để khởi động, cấp quyền. Khởi động sáu dịch vụ.
      3. Bước ba là sử dụng Ruby để quản lý dịch vụ Redis, thực hiện cluster, chạy lệnh tạo cluster. Tạo thành công. Sau đó có thể kiểm tra cluster bằng ./redis-cli -c -p 6379. -c đại diện cho cluster, -p đại diện cho cổng.
      4. Slots: Có 16384 slot, được tính toán bằng thuật toán CRC16 để xác định slot đó thuộc về Redis nào trong cluster.

      Tích hợp vào Spring: Tích hợp Redis vào dự án nghĩa là để Spring quản lý Redis.

      1. Tệp cấu hình: Cấu hình địa chỉ IP và cổng của Redis cluster.
      2. Quản lý lớp dao và lớp triển khai jedis, cấu hình hỗ trợ chú thích @Repository.
      3. Lớp triển khai có thể có lớp RedisClients thực sự gọi các phương thức setget của Redis.

      2.1.4.3. Truy vấn Solr

      Giới thiệu: Là một máy chủ ứng dụng tìm kiếm độc lập cấp doanh nghiệp, một máy chủ tìm kiếm mã nguồn mở của Apache, thực tế là một dự án Java, được triển khai trong Tomcat!

      Chủ yếu dựa trên HTTP và Apache Lucene. Hỗ trợ các giao diện chuẩn, hỗ trợ truy vấn HTTP, XML, JSON. Có thể phân trang, làm nổi bật, quản lý giao diện trực quan.

      Tìm kiếm toàn văn dựa trên chỉ mục. Cần xây dựng kho chỉ mục trước. Hiệu quả hơn LIKE, LIKE là truy vấn theo thứ tự và không có chỉ mục. Cải thiện trải nghiệm người dùng.

      Nguyên lý:

      Kho chỉ mục lưu trữ các trường chỉ mục: Solr có thể hiểu như một cơ sở dữ liệu --> đối tượng document có thể hiểu như một hàng dữ liệu trong bảng --> thuộc tính field có thể hiểu như một trường.

      Trong tệp cấu hình schema.xml, cấu hình fieldType làm bộ phân tích từ tiếng Trung và cấu hình fieldName làm trường truy vấn.

      Trong dự án ego, để truy vấn chi tiết sản phẩm, cần cấu hình các trường của sản phẩm. Có thể truy vấn theo từng trường, đồng thời có thể cấu hình thuộc tính copyField source để thực hiện truy vấn từ trên nhiều trường.

      Solr sẽ phân tách từ khóa tìm kiếm và tìm kiếm nội dung trong chỉ mục đã được xây dựng.

      Cài đặt Solr đơn lẻ:

      Cần có Tomcat và JDK. Sao chép và giải nén gói Solr, triển khai tệp war đã giải nén lên Tomcat.

      Sửa đổi tệp ./start.sh./shutdown.sh của Tomcat để chỉ định Tomcat cụ thể. Và sửa đổi đường dẫn kho chỉ mục trong tệp web.xml của Solr.

      Khởi động Tomcat, truy cập giao diện quản lý Solr nếu cài đặt thành công.

      Đây là nguyên lý cài đặt Solr, cấu hình kho chỉ mục và truy vấn.

      Solr cluster cần sự hỗ trợ của ZooKeeper. Vì Tomcat và Solr không có chức năng cluster.

      Một leader, hai slave. Mỗi slave quản lý hai Tomcat.

      Sao chép Tomcat và sửa đổi cổng --> Sửa đổi tệp ./start.sh./shutdown.sh của Tomcat --> Sửa đổi catalina.sh --> Sao chép và sửa đổi web.xml --> Sửa đổi cổng trong solr.xml và tương ứng với Tomcat. Khi kiểm thử, nhất định phải tắt tường lửa và bật ZooKeeper.

      Trong dự án ego-search, cần thêm phụ thuộc solr.jar vào pom.xml. Trong tệp cấu hình, cấu hình IP của ZooKeeper cluster.

      Quá trình triển khai truy vấn: Nhập từ khóa "điện thoại" vào ô tìm kiếm, nhấp vào tìm kiếm, "điện thoại" sẽ là từ khóa truy vấn trong Solr cluster. Ngoài ra, còn cần lấy page từ front-end, làm cơ sở cho việc phân trang của Solr.

      Tạo lớp thực thể để lưu trữ thông tin sản phẩm cần cho trang. Trong lớp triển khai nghiệp vụ, tạo tập hợp này, gán điều kiện truy vấn cho trường truy vấn, truy vấn tất cả các tập hợp sản phẩm phù hợp và lấy dữ liệu nổi bật. Sau đó, lặp qua tập hợp này, so sánh trường nổi bật, lấy tập hợp nổi bật, đưa tất cả các thuộc tính cần cho trang vào lớp thực thể, sau đó đưa vào tập hợp, gán cho bộ chứa cần thiết cho trang và trả về.

      2.1.5. MyCAT

      MySQL thông qua MyCAT cluster.

      MyCAT là một middleware cơ sở dữ liệu được viết bằng ngôn ngữ Java. Nó kết nối ứng dụng và cơ sở dữ liệu để tương tác dữ liệu.

      Vai trò của MyCAT: Khi lượng dữ liệu lớn, chia một cơ sở dữ liệu thành nhiều thư viện logic, tương đương với cluster cơ sở dữ liệu.

      • Phân chia cơ sở dữ liệu (Sharding Database): Một cơ sở dữ liệu được chia thành nhiều cơ sở dữ liệu logic thông qua MyCAT. Các cơ sở dữ liệu này được gọi chung là thư viện logic (theo chiều dọc - theo nghiệp vụ).
      • Phân chia bảng (Sharding Table): (Theo chiều ngang - theo thao tác).

      Cấu hình chính:

      • schema.xml: Cấu hình máy chủ đọc/ghi, tức là cơ sở dữ liệu Master/Slave của MySQL; định nghĩa thư viện logic, bảng logic.
      • server.xml: Định nghĩa thư viện logic, tên người dùng và mật khẩu để kết nối cơ sở dữ liệu.
      • rule.xml: Định nghĩa quy tắc phân chia của MyCAT, ví dụ: thuật toán crc32. Xem dữ liệu được chia thành thư viện logic nào.

      Cơ sở dữ liệu Master/Slave:

      Master để ghi dữ liệu, Slave để đọc dữ liệu.

      Cơ sở dữ liệu Master/Slave. Sửa đổi tệp cấu hình my.cnf, bật chức năng nhật ký và chỉ định server_id. Bởi vì Slave sao chép và đọc nhật ký thông qua các luồng IO và SQL để sao lưu. Sau đó, cần tạo người dùng và đồng thời chỉ định IP của Slave, để Slave có quyền sao lưu và truy cập cơ sở dữ liệu Master.

      2.1.6. Cuối cùng về Triển khai Dự án: Đóng gói Dubbo

      Sử dụng plugin Assembly của Maven: (1) Thêm phụ thuộc vào pom.xml: thông tin plugin đóng gói và tệp mô tả đóng gói assembly; (2) Tạo thư mục assembly trong thư mục gốc của dự án, và tạo tệp assembly.xml, sao chép thông tin cấu hình; quy định thư mục lib trong tệp tar.gz và quyền truy cập thư mục; (3) Chạy Run as --> Maven Install, sau đó tệp .tar.gz sẽ được tạo trong thư mục target. (4) Tải lên Linux và chạy ./start để khởi động dịch vụ.

      2.1.7. Nạp lại (Hot Deployment) (Triển khai Từ xa)

      1. Nạp lại: Trước tiên, cấu hình Tomcat trên Linux: vim tomcat-users.xml:
        <role rolename="manager-gui"/> <role rolename="manager-script"/> <user username="tomcat" password="tomcat" roles="manager-gui,manager-script"/>


        Khởi động lại Tomcat.
      2. Trong tệp pom.xml của dự án war cần triển khai:
        <port>8082</port>
        <path>/</path>
        Thêm cấu hình bên dưới.
        <username>tomcat</username>
        <password>tomcat</password>
        <url>http://192.168.26.150:8080/manager/text</url> --> manager/text là cố định, phần trước là IP và cổng của máy chủ nơi dự án sẽ được triển khai.

        Tiếp theo là triển khai tomcat7:redeploy sử dụng maven build...
      3. Kiểm tra xem đã triển khai thành công hay chưa: Tìm trong thư mục Tomcat, thư mục webapps, thư mục ROOT: cd /WEB-INF/lib, kiểm tra xem có tệp jar của dự án hay không.
      4. Truy cập: Có thể truy cập trực tiếp trên trình duyệt http://192.168.26.150:8080/
      5. Sửa đổi ánh xạ: Cấu hình ánh xạ ảo C:\Windows\System32\drivers\etc\hosts 192.168.26.150 www.ego.com
      6. Nếu không ghi rõ cổng, mặc định là cổng 80. Sửa đổi cổng Tomcat trên máy chủ Linux thành 80.
      7. Cần khởi động lại Tomcat. Truy cập qua tên miền.
      8. Trong tệp server.xml, sửa đổi cổng Tomcat.
      9. Thư mục gốc của Tomcat: Catalina
        • catalina.policy
        • catalina.properties
        • context.xml
        • logging.properties
        • server.xml
        • tomcat-users.xml
        • web.xml
      10. Theo tình hình, có thể sử dụng Nginx để proxy các dịch vụ có áp lực lớn (cân bằng tải).

      2.2. Số Cổng Các Thành phần Phổ biến

      Tên thành phần Cổng mặc định
      mysql 3306
      oracle 1521
      SqlServer 1433
      redis 6379 (Mặc định có 16384 slot)
      zookeeper 2181 (Cổng giao thức truyền thông: 20880)
      tomcat 8080
      nginx 80
      ftp 21
      sftp 22
      nexus (kho cục bộ) 8081
      svn 3690
      mycat 8066

Thẻ: SSM Spring mybatis Spring MVC AOP

Đăng vào ngày 9 tháng 8 lúc 11:11