模仿天貓實戰【SSM版】——專案起步

weixin_34365417發表於2018-04-27
7896890-3eee3c0023557f8e.png

前言:現在自己的學習似乎遇到了瓶頸,感覺學習了 SSM 之後有一些迷茫,不知道接下來該往哪裡去努力了,我覺得這是個很不好的狀態,為了度過這段時期,我準備把天貓模仿下來(給自己找點事做)之後開始去鞏固 Java 的基礎知識,也準備好暑假去找實習。

第一步:需求分析

首先要確定要實現哪些功能,需要對需求進行完整的分析,才能在編寫專案的時候有條不紊,我們的目的很明確:就是模仿天貓前端 + 自己實現後端。並且盡最大努力去降低這個專案的複雜度(畢竟高深的東西不懂)。

前端需求分析

規定:全天貓沒有店鋪,就只有唯一一家叫做 Tmall 的商家,賣所有的東西。

  • 1.資料的顯示:

首頁資料顯示分析:

首先是搜尋欄下方的九個商品,需要從資料庫中取出銷量最高的幾個產品,關於標紅的關鍵字,是要滿足一定條件的,比如:這一個星期內銷量超過多少...

7896890-ee6c3bed893d7229.png

接著是分類導航欄,首先是商品分類右邊固定的兩個連結【天貓超市】和【天貓國際】,還有緊跟著的八個超鏈,這個可以設計為一個單表,儲存它顯示的文字和連結過去的地址,然後是具體的 16 個分類以及輪播:

7896890-e85879cb8e4d5aa8.png

下面的具體產品展示比較複雜,我們可以自己做一下簡化,比如就展示幾個產品比較多的固定的幾個分類就好了,其他的就直接捨棄:

7896890-84ef80bc6a962d35.png
  • 總結: 總之就是需要顯示各種資料庫中的資料
  • 2.登入/註冊頁

需要有一個登入/註冊頁,能夠完成使用者的登入和註冊功能,並能提供基礎的例如判斷空值等功能。

  • 3.產品搜尋頁
7896890-3740347e272b1ef0.png

左上角的圖示我們可以統一簡化成 Tmall 的圖片,商品圖片,我們可以整個大分類使用一張圖,主要就是實現排序功能還有搜尋功能

  • 4.產品展示頁

天貓原生的產品展示頁有些複雜,我們可以自己簡化一下,就不要選這麼多東西,都是一口價,

7896890-6e04b72b9365b941.png

另外下方規格引數和評價都不能省略:

7896890-67d2078a8f016c95.png
  • 5.購物車/購買頁面

第二步:表結構設計

根據對於前端的分析,資料庫有了一些眉目,為了簡化專案的難度,所以我們需要自己想點辦法,先來構思一下大概需要一些什麼樣的表:

7896890-70e86e80be27582b.png

我大概就想出來需要用到這些表,我們一個一個來建立它們:

表一:分類表

首先我們需要一個表來儲存我們的分類資訊,也就是【女裝/內衣】、【男裝/運動戶外】在內的 16 個分類,為了高度一致,這 16 個分類不能多也不能少。

7896890-5ac9b6db283570f1.png

為了簡化任務,可以觀察出,【熱門手機】、【特色手機】分欄下的東西都是【手機/數碼/電腦辦公】類別裡的東西,所以我們直接砍掉,右邊的一些圖片超鏈也給直接砍掉,我們規定每一行顯示的產品數目就可以了,這樣就簡單多了。

CREATE TABLE category (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  name varchar(255) NOT NULL COMMENT '分類的名字',
  PRIMARY KEY (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

表二:商品分類右邊的超連結串列

即在【天貓國際】右邊的 8 個超鏈,我們單獨新建一個表來儲存超鏈顯示的文字和連結的地址,這樣就可以任意的修改其內容:

7896890-4c4dd522d7725685.png

百度翻譯【推薦連結】翻譯為【Referral links】,那我們也這麼給我們的表命名好了:

CREATE TABLE referal_link (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  text varchar(255) NOT NULL COMMENT '超鏈顯示的文字',
  link varchar(255) NOT NULL COMMENT '超鏈的地址',
  PRIMARY KEY (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

表三:產品表

每個分類下都要一定的產品,這些產品還有自己的一些屬性,所以另外需要屬性表,這個表另外建立,我們先來觀察一下一個產品表需要一些什麼東西:

7896890-1c882a1c5e908c2a.png
  • 用於展示的 5 張圖片
  • 產品名稱
  • 小標題(即名稱下面一排標紅的小字)
  • 價格(就一口價,沒別的)
  • 銷量(別月銷量了,能簡化就簡化一下)
  • 累計評價(還需要設計一個評價表)
  • 庫存
  • 屬性(需要關聯另外的屬性表)
CREATE TABLE product (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  name varchar(255) NOT NULL COMMENT '產品的名稱',
  sub_title varchar(255) DEFAULT NULL COMMENT '小標題',
  price float DEFAULT NULL COMMENT '價格',
  sale int(11) DEFAULT NULL COMMENT '銷量',
  stock int(11) DEFAULT NULL COMMENT '庫存',
  category_id int(11) DEFAULT NULL COMMENT '對應的分類id',
  PRIMARY KEY (id),
  CONSTRAINT fk_product_category FOREIGN KEY (category_id) REFERENCES category (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
  • 注意: 其中產品圖片,累計評價,屬性都作為單獨的表存在並讓當前表的 id 作為外來鍵

表四:屬性表

7896890-755570d44559ce1a.png

去掉詳細的規格引數劃分,其實屬性也就是一個名字而已(簡化簡化簡化)。

CREATE TABLE property (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  name varchar(255) DEFAULT NULL COMMENT '屬性名稱',
  product_id int(11) NOT NULL COMMENT '對應的產品id',
  PRIMARY KEY (id),
  CONSTRAINT fk_property_product FOREIGN KEY (product_id) REFERENCES product(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  • 突然想到的問題:
    每一個產品的屬性其實是很多的,如果每一個產品都對應很多屬性的話,對於天貓這樣的資料量來說,應該會讓資料庫爆炸的吧...
  • 改進方法:
    將屬性表關聯到 category 表上,因為其實每一個分類下的產品的屬性差不多!

修改資料庫

根據以上問題,修改一下資料庫表之間的關係

7896890-8dcfd056d47a8b0f.png

並將屬性表的外來鍵修改為 category 的主鍵:

CREATE TABLE property (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  name varchar(255) DEFAULT NULL COMMENT '屬性名稱',
  category_id int(11) NOT NULL COMMENT '對應的分類id',
  PRIMARY KEY (id),
  CONSTRAINT fk_property_category FOREIGN KEY (category_id) REFERENCES category(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

表五:屬性值表

其中就是儲存了對應屬性的值,並且應該有兩個外來鍵,一個指向 Property 表,而另一個則指向 Product 表

CREATE TABLE property_value (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  product_id int(11) NOT NULL COMMENT '對應產品id',
  properti_id int(11) NOT NULL COMMENT '對應屬性id',
  value varchar(255) DEFAULT NULL COMMENT '具體的屬性值',
  PRIMARY KEY (id),
  CONSTRAINT fk_property_value_property FOREIGN KEY (properti_id) REFERENCES property (id),
  CONSTRAINT fk_property_value_product FOREIGN KEY (product_id) REFERENCES product (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

表六:產品圖片表

這個表名義上是儲存了產品的圖片,其實只是儲存了產品圖片的位置即圖片名稱,我們可以規定所有的產品圖片都放在一個統一的資料夾下面,然後通過 id 來獲取對應名稱的圖片

CREATE TABLE product_image (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  product_id int(11) DEFAULT NULL COMMENT '對應的產品id',
  PRIMARY KEY (id),
  CONSTRAINT fk_product_image_product FOREIGN KEY (product_id) REFERENCES product (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  • 注意: 我們通過把產品圖片的檔案命名為 id.jpg ,然後通過相對路徑來獲取到產品圖片

表七:使用者表

使用者表很簡單,也沒有許可權之類的東西:

CREATE TABLE user (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  name varchar(255) NOT NULL COMMENT '使用者名稱稱',
  password varchar(255) NOT NULL COMMENT '使用者密碼',
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  • 我們或許會在之後把密碼弄成 “*********” 這種形式的,但是現在一切為了簡單!

表八:評價表

7896890-048235277c4287f2.png

評價表對應了使用者和產品兩個表,也比較簡單,我們為了簡單,把上面紅色的部分全部砍掉,因為沒有商家,所以也不需要回複使用者的評價,都砍掉砍掉!

CREATE TABLE review (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  content varchar(4000) DEFAULT NULL COMMENT '評價內容',
  user_id int(11) NOT NULL COMMENT '對應的使用者id',
  product_id int(11) NOT NULL COMMENT '對應的產品id',
  createDate datetime DEFAULT NULL COMMENT '評價時間',
  PRIMARY KEY (id),
  CONSTRAINT fk_review_product FOREIGN KEY (product_id) REFERENCES product (id),
    CONSTRAINT fk_review_user FOREIGN KEY (user_id) REFERENCES user (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

表九:訂單表

由於 Order 是 MySql 的一個關鍵字,所以我們在訂單表的最後新增一個下劃線:

CREATE TABLE order_ (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  order_code varchar(255) NOT NULL COMMENT '訂單號',
  address varchar(255) NOT NULL COMMENT '收貨地址',
  post varchar(255) NOT NULL COMMENT '郵編',
  receiver varchar(255) NOT NULL COMMENT '收貨人姓名',
  mobile varchar(255) NOT NULL COMMENT '手機號碼',
  user_message varchar(255) NOT NULL COMMENT '使用者備註的資訊',
  create_date datetime NOT NULL COMMENT '訂單建立時間',
  pay_date datetime DEFAULT NULL COMMENT '訂單支付時間',
  delivery_date datetime DEFAULT NULL COMMENT '發貨日期',
  confirm_date datetime DEFAULT NULL COMMENT '確認收貨日期',
  user_id int(11) DEFAULT NULL COMMENT '對應的使用者id',
  status varchar(255) NOT NULL COMMENT '訂單狀態',
  PRIMARY KEY (id),
  CONSTRAINT fk_order_user FOREIGN KEY (user_id) REFERENCES user (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

表十:訂單項表

一個訂單裡面可能有多個訂單項,一個產品也可能對應多個訂單項,所以這個表應該有兩個外來鍵:

CREATE TABLE order_item (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  product_id int(11) NOT NULL COMMENT '對應產品id',
  order_id int(11) NOT NULL COMMENT '對應訂單id',
  number int(11) DEFAULT NULL COMMENT '對應產品購買的數量',
  PRIMARY KEY (id) COMMENT '郵編',
  CONSTRAINT fk_order_item_product FOREIGN KEY (product_id) REFERENCES product (id),
  CONSTRAINT fk_order_item_order FOREIGN KEY (order_id) REFERENCES order_ (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

彙總:

我們在建立表之前,應該建立一個新的資料庫,並命名為【tmall_ssm】

DROP DATABASE IF EXISTS tmall_ssm;
CREATE DATABASE tmall_ssm DEFAULT CHARACTER SET utf8;

將這十個表匯個總就是:

DROP DATABASE IF EXISTS tmall_ssm;
CREATE DATABASE tmall_ssm DEFAULT CHARACTER SET utf8;

use tmall_ssm;

CREATE TABLE category (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  name varchar(255) NOT NULL COMMENT '分類的名字',
  PRIMARY KEY (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

CREATE TABLE referal_link (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  text varchar(255) NOT NULL COMMENT '超鏈顯示的文字',
  link varchar(255) NOT NULL COMMENT '超鏈的地址',
  PRIMARY KEY (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

CREATE TABLE product (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  name varchar(255) NOT NULL COMMENT '產品的名稱',
  sub_title varchar(255) DEFAULT NULL COMMENT '小標題',
  price float DEFAULT NULL COMMENT '價格',
  sale int(11) DEFAULT NULL COMMENT '銷量',
  stock int(11) DEFAULT NULL COMMENT '庫存',
  category_id int(11) DEFAULT NULL COMMENT '對應的分類id',
  PRIMARY KEY (id),
  CONSTRAINT fk_product_category FOREIGN KEY (category_id) REFERENCES category (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

CREATE TABLE property (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  name varchar(255) DEFAULT NULL COMMENT '屬性名稱',
  category_id int(11) NOT NULL COMMENT '對應的分類id',
  PRIMARY KEY (id),
  CONSTRAINT fk_property_category FOREIGN KEY (category_id) REFERENCES category(id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE property_value (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  product_id int(11) NOT NULL COMMENT '對應產品id',
  properti_id int(11) NOT NULL COMMENT '對應屬性id',
  value varchar(255) DEFAULT NULL COMMENT '具體的屬性值',
  PRIMARY KEY (id),
  CONSTRAINT fk_property_value_property FOREIGN KEY (properti_id) REFERENCES property (id),
  CONSTRAINT fk_property_value_product FOREIGN KEY (product_id) REFERENCES product (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

CREATE TABLE product_image (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  product_id int(11) DEFAULT NULL COMMENT '對應的產品id',
  PRIMARY KEY (id),
  CONSTRAINT fk_product_image_product FOREIGN KEY (product_id) REFERENCES product (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE user (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  name varchar(255) NOT NULL COMMENT '使用者名稱稱',
  password varchar(255) NOT NULL COMMENT '使用者密碼',
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE review (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  content varchar(4000) DEFAULT NULL COMMENT '評價內容',
  user_id int(11) NOT NULL COMMENT '對應的使用者id',
  product_id int(11) NOT NULL COMMENT '對應的產品id',
  createDate datetime DEFAULT NULL COMMENT '評價時間',
  PRIMARY KEY (id),
  CONSTRAINT fk_review_product FOREIGN KEY (product_id) REFERENCES product (id),
  CONSTRAINT fk_review_user FOREIGN KEY (user_id) REFERENCES user (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

CREATE TABLE order_ (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  order_code varchar(255) NOT NULL COMMENT '訂單號',
  address varchar(255) NOT NULL COMMENT '收貨地址',
  post varchar(255) NOT NULL COMMENT '郵編',
  receiver varchar(255) NOT NULL COMMENT '收貨人姓名',
  mobile varchar(255) NOT NULL COMMENT '手機號碼',
  user_message varchar(255) NOT NULL COMMENT '使用者備註的資訊',
  create_date datetime NOT NULL COMMENT '訂單建立時間',
  pay_date datetime DEFAULT NULL COMMENT '訂單支付時間',
  delivery_date datetime DEFAULT NULL COMMENT '發貨日期',
  confirm_date datetime DEFAULT NULL COMMENT '確認收貨日期',
  user_id int(11) DEFAULT NULL COMMENT '對應的使用者id',
  status varchar(255) NOT NULL COMMENT '訂單狀態',
  PRIMARY KEY (id),
  CONSTRAINT fk_order_user FOREIGN KEY (user_id) REFERENCES user (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

CREATE TABLE order_item (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一索引id',
  product_id int(11) NOT NULL COMMENT '對應產品id',
  order_id int(11) NOT NULL COMMENT '對應訂單id',
  number int(11) DEFAULT NULL COMMENT '對應產品購買的數量',
  PRIMARY KEY (id) COMMENT '郵編',
  CONSTRAINT fk_order_item_product FOREIGN KEY (product_id) REFERENCES product (id),
  CONSTRAINT fk_order_item_order FOREIGN KEY (order_id) REFERENCES order_ (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

直接複製進 MySql 中執行,就能看到我們建立好的十個資料庫:

7896890-559c02b039ba4d57.png

第三步:建立 SSM 開發環境

根據之前我寫過的博文:IDEA 整合 SSM 搭建好 SSM 開發環境,這裡給出完整的專案結構和 pom.xml 檔案:

  • 完整的專案結構:
7896890-7371e706e33bf2f4.png
  • pom.xml 檔案:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <packaging>war</packaging>

    <name>wmyskxz</name>
    <groupId>cn.wmyskxz</groupId>
    <artifactId>wmyskxz</artifactId>
    <version>1.0-SNAPSHOT</version>

    <build>
        <plugins>
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>maven-jetty-plugin</artifactId>
                <version>6.1.7</version>
                <configuration>
                    <connectors>
                        <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
                            <port>8888</port>
                            <maxIdleTime>30000</maxIdleTime>
                        </connector>
                    </connectors>
                    <webAppSourceDirectory>${project.build.directory}/${pom.artifactId}-${pom.version}
                    </webAppSourceDirectory>
                    <contextPath>/</contextPath>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <properties>
        <!-- 設定專案編碼編碼 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <!-- spring版本號 -->
        <spring.version>4.3.5.RELEASE</spring.version>
        <!-- mybatis版本號 -->
        <mybatis.version>3.4.1</mybatis.version>
    </properties>

    <dependencies>

        <!-- pageHelper -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>5.1.2-beta</version>
        </dependency>

        <!--jsqlparser-->
        <dependency>
            <groupId>com.github.jsqlparser</groupId>
            <artifactId>jsqlparser</artifactId>
            <version>1.0</version>
        </dependency>

        <!-- jstl標籤 -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.taglibs</groupId>
            <artifactId>taglibs-standard-impl</artifactId>
            <version>1.2.5</version>
        </dependency>

        <!-- java ee -->
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0</version>
        </dependency>

        <!-- 單元測試 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <!-- 實現slf4j介面並整合 -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.2</version>
        </dependency>

        <!-- JSON -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.8.7</version>
        </dependency>


        <!-- 資料庫 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.41</version>
            <scope>runtime</scope>
        </dependency>

        <!-- 資料庫連線池 -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>

        <!-- MyBatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>${mybatis.version}</version>
        </dependency>

        <!-- mybatis/spring整合包 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.1</version>
        </dependency>

        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>

    </dependencies>

</project>

MyBatis 逆向工程

按照正常的流程,我們應該去建立資料庫對應的 POJO 和 DAO 類還有對應的 mapper 對映檔案,按照上面的分析我們一共有十張表,想象一下為這十張表做這些無技術含量的機械化的繁雜的工作是多麼頭疼的一件事,我們希望的是:有人幫我自動建立好這些!

  • MyBatis 官方提供了一種名為 “逆向工程” 的機制,其可以針對資料庫中的單表自動生成 MyBatis 執行所需要的程式碼
  • 包括:
    Java 實體類、Mapper對映配置、Mapper代理介面

第一步:新增必要的 jar 包

我們使用逆向工程,需要先匯入 Mybatis Generator 的官方包,由於我們使用的是 Maven 搭建的 SSM 專案,所有我們可以去 Maven 的官網去查詢需要的相關包:http://mvnrepository.com/

7896890-048c0f3c81ce740d.png

戳進去點選最新的包:

7896890-8b63aa02666d95ed.png

就可以在下方找到 Maven 依賴新增的語句:

7896890-6242885479edbf79.png

直接粘進 pom.xml 就可以了,這裡就不演示了。

第二步:generatorConfig.xml

在【resources】下建立 generatorConfig.xml 配置檔案,該配置檔案說明了一些逆向工程的細節:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>

    <context id="DB2Tables" targetRuntime="MyBatis3">

        <!-- 是否去除自動生成的程式碼中的註釋 true:是 false:否-->
        <commentGenerator>
            <property name="suppressDate" value="true"/>
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>

        <!-- 資料庫連線資訊:驅動類、連線地址、使用者名稱、密碼 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost/tmall_ssm"
                        userId="root" password="root">
        </jdbcConnection>

        <!-- 預設 false,把 JDBC DECIMAL 和 NUMERIC 型別解析為 Integer
             為 true 時解析為 java.math.BigDecimal -->
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>

        <!-- targetProject:生成 POJO 類的位置 -->
        <javaModelGenerator targetPackage="cn.wmyskxz.pojo" targetProject="src/main/java">
            <!-- enableSubPackages:是否讓 schema 作為包的字尾-->
            <property name="enableSubPackages" value="false"/>
            <!-- trimStrings:從資料庫返回的值被清理前後的空格 -->
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>

        <!-- targetProject:生成xml對映檔案存放位置 -->
        <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
            <!-- enableSubPackages:是否讓 schema 作為包的字尾-->
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>

        <!-- targetProject:生成mapper類存放位置 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="cn.wmyskxz.mapper" targetProject="src/main/java">
            <!-- enableSubPackages:是否讓 schema 作為包的字尾-->
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>

        <!--生成對應表及類名
            tableName:要生成的表名
            domainObjectName:生成後的例項名
            enableCountByExample:Count語句中加入where條件查詢,預設為true開啟
            enableUpdateByExample:Update語句中加入where條件查詢,預設為true開啟
            enableDeleteByExample:Delete語句中加入where條件查詢,預設為true開啟
            enableSelectByExample:Select多條語句中加入where條件查詢,預設為true開啟
            selectByExampleQueryId:Select單個物件語句中加入where條件查詢,預設為true開啟
        -->
        <table tableName="category" domainObjectName="Category" enableCountByExample="false"
               enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="true"
               selectByExampleQueryId="false">
            <!-- 使用資料庫中實際的欄位名作為生成的實體類的屬性 -->
            <property name="useActualColumnNames" value="true"/>
            <!-- 使用自增長鍵 -->
            <property name="my.isgen.usekeys" value="true"/>
            <generatedKey column="id" sqlStatement="JDBC"/>
        </table>

        <table tableName="property" domainObjectName="Property" enableCountByExample="false"
               enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="true"
               selectByExampleQueryId="false">
            <property name="useActualColumnNames" value="true"/>
            <property name="my.isgen.usekeys" value="true"/>
            <generatedKey column="id" sqlStatement="JDBC"/>
        </table>

        <table tableName="product" domainObjectName="Product" enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="true" selectByExampleQueryId="false">
            <property name="my.isgen.usekeys" value="true"/>
            <property name="useActualColumnNames" value="true"/>
            <generatedKey column="id" sqlStatement="JDBC"/>
        </table>

        <table tableName="product_image" domainObjectName="ProductImage" enableCountByExample="false"
               enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="true"
               selectByExampleQueryId="false">
            <property name="my.isgen.usekeys" value="true"/>
            <property name="useActualColumnNames" value="true"/>
            <generatedKey column="id" sqlStatement="JDBC"/>
        </table>

        <table tableName="order_" domainObjectName="Order" enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="true" selectByExampleQueryId="false">
            <property name="my.isgen.usekeys" value="true"/>
            <property name="useActualColumnNames" value="true"/>
            <generatedKey column="id" sqlStatement="JDBC"/>
        </table>

        <table tableName="property_value" domainObjectName="PropertyValue" enableCountByExample="false"
               enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="true"
               selectByExampleQueryId="false">
            <property name="my.isgen.usekeys" value="true"/>
            <property name="useActualColumnNames" value="true"/>
            <generatedKey column="id" sqlStatement="JDBC"/>
        </table>

        <table tableName="review" domainObjectName="Review" enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="true" selectByExampleQueryId="false">
            <property name="my.isgen.usekeys" value="true"/>
            <property name="useActualColumnNames" value="true"/>
            <generatedKey column="id" sqlStatement="JDBC"/>
        </table>

        <table tableName="user" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false"
               enableDeleteByExample="false" enableSelectByExample="true" selectByExampleQueryId="false">
            <property name="my.isgen.usekeys" value="true"/>
            <property name="useActualColumnNames" value="true"/>
            <generatedKey column="id" sqlStatement="JDBC"/>
        </table>

        <table tableName="order_item" domainObjectName="OrderItem" enableCountByExample="false"
               enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="true"
               selectByExampleQueryId="false">
            <property name="my.isgen.usekeys" value="true"/>
            <property name="useActualColumnNames" value="true"/>
            <generatedKey column="id" sqlStatement="JDBC"/>
        </table>

        <table tableName="referal_link" domainObjectName="ReferalLink" enableCountByExample="false"
               enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="true"
               selectByExampleQueryId="false">
            <property name="my.isgen.usekeys" value="true"/>
            <property name="useActualColumnNames" value="true"/>
            <generatedKey column="id" sqlStatement="JDBC"/>
        </table>
    </context>
</generatorConfiguration>

這樣配置檔案也就編寫好了

第三步:逆向資料檔案生成類

在編寫完配置檔案只有,就需要載入該配置檔案,利用逆向工程的機制來對資料庫的各個表進行一系列檔案的生成,我們在【test/java】包下建立【TestMyBatisGenerator】類:

import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.api.ShellCallback;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * 逆向工程測試類
 *
 * @author: @我沒有三顆心臟
 * @create: 2018-04-27-上午 8:26
 */
public class TestMybatisGenerator {

    public static void main(String[] args) throws Exception {
        // warnings 為用於放置生成過程中警告資訊的集合物件
        List<String> warnings = new ArrayList<String>();
        // 指定是否覆蓋重名檔案
        boolean overwrite = true;
        // 載入配置檔案
        File configFile = new File(MyBatisGenerator.class.getClassLoader().getResource("generatorConfig.xml").toURI());
        // 配置解析類
        ConfigurationParser cp = new ConfigurationParser(warnings);
        // 配置解析類解析配置檔案並生成 Configuration 配置物件
        Configuration config = cp.parseConfiguration(configFile);
        // ShellCallback 負責如何處理重複檔案
        ShellCallback callback = new DefaultShellCallback(overwrite);
        // 逆向工程物件
        MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
        // 執行逆向檔案生成操作
        myBatisGenerator.generate(null);
        // 列印提示資訊
        System.out.println("MyBatis 逆向工程執行成功,重新整理專案檢視檔案!");
    }
}

執行該測試類,就能看見自動生成的檔案:

7896890-207d1abeb35a84c0.png
  • Oh!這真的是太爽了!突然開心(**)

看一下自動生成的檔案

以 Category 為例,我們來看一下自動生成的檔案:

  • Category 實體類:
package cn.wmyskxz.pojo;

public class Category {
    private Integer id;

    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name == null ? null : name.trim();
    }
}
  • CategoryMapper 對映類:
package cn.wmyskxz.mapper;

import cn.wmyskxz.pojo.Category;
import cn.wmyskxz.pojo.CategoryExample;
import java.util.List;

public interface CategoryMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(Category record);

    int insertSelective(Category record);

    List<Category> selectByExample(CategoryExample example);

    Category selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(Category record);

    int updateByPrimaryKey(Category record);
}
  • CategoryMapper.xml 對映檔案:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.wmyskxz.mapper.CategoryMapper">
    <resultMap id="BaseResultMap" type="cn.wmyskxz.pojo.Category">
        <id column="id" jdbcType="INTEGER" property="id"/>
        <result column="name" jdbcType="VARCHAR" property="name"/>
    </resultMap>
    <sql id="Example_Where_Clause">
        <where>
            <foreach collection="oredCriteria" item="criteria" separator="or">
                <if test="criteria.valid">
                    <trim prefix="(" prefixOverrides="and" suffix=")">
                        <foreach collection="criteria.criteria" item="criterion">
                            <choose>
                                <when test="criterion.noValue">
                                    and ${criterion.condition}
                                </when>
                                <when test="criterion.singleValue">
                                    and ${criterion.condition} #{criterion.value}
                                </when>
                                <when test="criterion.betweenValue">
                                    and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
                                </when>
                                <when test="criterion.listValue">
                                    and ${criterion.condition}
                                    <foreach close=")" collection="criterion.value" item="listItem" open="("
                                             separator=",">
                                        #{listItem}
                                    </foreach>
                                </when>
                            </choose>
                        </foreach>
                    </trim>
                </if>
            </foreach>
        </where>
    </sql>
    <sql id="Base_Column_List">
    id, name
  </sql>
    <select id="selectByExample" parameterType="cn.wmyskxz.pojo.CategoryExample" resultMap="BaseResultMap">
        select
        <if test="distinct">
            distinct
        </if>
        'false' as QUERYID,
        <include refid="Base_Column_List"/>
        from category
        <if test="_parameter != null">
            <include refid="Example_Where_Clause"/>
        </if>
        <if test="orderByClause != null">
            order by ${orderByClause}
        </if>
    </select>
    <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from category
        where id = #{id,jdbcType=INTEGER}
    </select>
    <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
    delete from category
    where id = #{id,jdbcType=INTEGER}
  </delete>
    <insert id="insert" keyColumn="id" keyProperty="id" parameterType="cn.wmyskxz.pojo.Category"
            useGeneratedKeys="true">
    insert into category (name)
    values (#{name,jdbcType=VARCHAR})
  </insert>
    <insert id="insertSelective" keyColumn="id" keyProperty="id" parameterType="cn.wmyskxz.pojo.Category"
            useGeneratedKeys="true">
        insert into category
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="name != null">
                name,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="name != null">
                #{name,jdbcType=VARCHAR},
            </if>
        </trim>
    </insert>
    <update id="updateByPrimaryKeySelective" parameterType="cn.wmyskxz.pojo.Category">
        update category
        <set>
            <if test="name != null">
                name = #{name,jdbcType=VARCHAR},
            </if>
        </set>
        where id = #{id,jdbcType=INTEGER}
    </update>
    <update id="updateByPrimaryKey" parameterType="cn.wmyskxz.pojo.Category">
    update category
    set name = #{name,jdbcType=VARCHAR}
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>

其中就只有對映檔案稍微有些複雜,但細看下來其實跟我們自己寫的差不多,甚至自動生成的完成得更好。

xxxExample

MybatisGenerator會生成一個類叫做XXXXExample的。,它的作用是進行排序,條件查詢的時候使用。

這裡有詳細的說明,瞭解一下就好了:戳這裡

第四步:測試

我們這裡僅僅就用 CategoryMapper 對映類來進行簡單測試了:

@Autowired
CategoryMapper categoryMapper;

@Test
public void test() {
    Category category = new Category();
    category.setName("分類1");
    categoryMapper.insert(category);
}

由於我們使用了自增長鍵 id ,所以僅僅只需要提供 name 屬性就可以了,執行,可以看到資料庫中有正確的資料:

7896890-b1e9cbc59225eb31.png

總結

根據以上的 “折騰” 算是完成了專案的起步工作了吧,我是一邊寫專案一邊寫部落格的,所以可能有時候想著想著寫著寫著思緒會有點飄,寫得凌亂,這也是沒有辦法的事,不管寫得好還是差我都希望能記錄下來,這些都是屬於我自己的思路和學習路程。

歡迎轉載,轉載請註明出處!
簡書ID:@我沒有三顆心臟
github:wmyskxz
歡迎關注公眾微訊號:wmyskxz_javaweb
分享自己的Java Web學習之路以及各種Java學習資料

相關文章