(四)spring boot + jpa + mysql 后臺管理系統(tǒng)

上篇文章:http://www.reibang.com/p/f062c9ff7b48
這一篇主要是完成spring boot 與 mysql的連接,并使用jpa八回,來完成一個(gè)后臺管理系統(tǒng)的增刪改查功能缠诅。
先來看最后的效果圖:

后臺管理系統(tǒng).png

前后臺分離后管引,每個(gè)人的習(xí)慣也不一樣,有的喜歡從前臺開始寫拱烁,有的喜歡從后臺開始寫噩翠,而我習(xí)慣從后往前寫伤锚。
我們先來看后端代碼結(jié)構(gòu):
代碼結(jié)構(gòu)

pom.xml

<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>demo.ptt</groupId>
    <artifactId>springDemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>springDemo</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>1.8</java.version>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
    </parent>

    <dependencies>
        <!-- test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- thymeleaf模版 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- 熱部署 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

重新創(chuàng)建一個(gè)控制器:ContractController猛们,增刪改查都在這里面弯淘。
ContractController.java

package demo.ptt.console.controllers;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import demo.ptt.console.dto.ExecuteResult;
import demo.ptt.console.po.Contract;
import demo.ptt.console.services.ContractServer;

@RestController
@RequestMapping("contract")
public class ContractController {

    @Autowired
    private ContractServer server;

    @PostMapping("save")
    public ExecuteResult<?> save(@RequestBody Contract param) {
        return server.save(param);
    }

    @PostMapping("findAll")
    public @ResponseBody List<Contract> findAll() {
        return server.findAll();
    }

    @GetMapping("remove/{id}")
    public ExecuteResult<?> remove(@PathVariable String id) {
        return server.remove(id);
    }

}

其中控制器中用到了一個(gè)封裝類
ExecuteResult.java
package demo.ptt.console.dto;

import java.io.Serializable;

public final class ExecuteResult<T> implements Serializable {

/**
 * 
 */
private static final long serialVersionUID = -4467073382353735654L;

/**
 * 執(zhí)行成功
 */
private boolean success;

private T value;

/**
 * 錯(cuò)誤碼
 */
private int errorCode;

/**
 * 錯(cuò)誤信息
 */
private String message;

public boolean isSuccess() {
    return success;
}

public T getValue() {
    return value;
}

public void setValue(T value) {
    this.value = value;
}

public int getErrorCode() {
    return errorCode;
}

public String getMessage() {
    return message;
}

private ExecuteResult() {

}

public static <T> ExecuteResult<T> ok() {
    ExecuteResult<T> result = new ExecuteResult<>();
    result.errorCode = 0;
    result.success = true;
    return result;
}

public static <T> ExecuteResult<T> ok(T value) {
    ExecuteResult<T> result = new ExecuteResult<T>();
    result.errorCode = 0;
    result.success = true;
    result.value = value;
    return result;
}

public static <T> ExecuteResult<T> fail(String message) {
    ExecuteResult<T> result = new ExecuteResult<>();
    result.errorCode = -1;
    result.success = false;
    result.message = message;
    return result;
}

public static <T> ExecuteResult<T> fail(int errorCode) {
    ExecuteResult<T> result = new ExecuteResult<>();
    result.errorCode = errorCode;
    result.success = false;
    return result;
}

public static <T> ExecuteResult<T> fail(int errorCode, String message) {
    ExecuteResult<T> result = new ExecuteResult<>();
    result.errorCode = errorCode;
    result.success = false;
    result.message = message;
    return result;
}

}
它可以返回我們的處理狀態(tài),在前端顯示态鳖。
ContractServer.java

package demo.ptt.console.services;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ResponseBody;

import demo.ptt.console.dto.ExecuteResult;
import demo.ptt.console.po.Contract;
import demo.ptt.console.repository.ContractRepository;

@Service
public class ContractServer {

    @Autowired
    private ContractRepository repository;

    public ExecuteResult<?> save(Contract param) {
        if (param == null) {
            return ExecuteResult.fail("參數(shù)為空");
        }
        repository.save(param);
        return ExecuteResult.ok();
    }

    public @ResponseBody List<Contract> findAll() {
        return repository.findAll();
    }
    
    public ExecuteResult<?> remove(String id) {
        if (StringUtils.isEmpty(id)) {
            return ExecuteResult.fail("參數(shù)為空");
        }
        Contract entity = repository.findOne(id);
        if (entity != null) {
            repository.delete(id);;
        }
        return ExecuteResult.ok();
    }

}

ContractRepository.java

package demo.ptt.console.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import demo.ptt.console.po.Contract;

public interface ContractRepository extends JpaRepository<Contract, String> {

}

Contract.java

package demo.ptt.console.po;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;

@Entity
@Table(name = "t_contract")
public class Contract {
    
    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    @Column(name = "contract_id", length = 36)
    public String id;
    
    /**
     * 姓名
     */
    @Column(name = "name", length = 50)
    public String name;
    
    /**
     * 姓別
     */
    @Column(name = "sex", length = 50)
    public String sex;
    
    /**
     * 手機(jī)號
     */
    @Column(name = "phone", length = 50)
    public String phone;
    
    /**
     * 身份證號
     */
    @Column(name = "id_card", length = 50)
    public String idCard;
    
    /**
     * 住址
     */
    @Column(name = "address", length = 50)
    public String address;
    
    /**
     * 省略 get  set
     */

}

除了這些以外,我們還需要添加配置:
application.properties

server.port=18062  
spring.profiles.active=dev

spring.datasource.initialize=false
spring.datasource.url=jdbc:mysql://localhost:3306/www
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update

其中:

spring.datasource.initialize=false
spring.datasource.url=jdbc:mysql://localhost:3306/www
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

是連接數(shù)據(jù)庫的配置邦泄,我們需要在本地?cái)?shù)據(jù)庫創(chuàng)建www這個(gè)數(shù)據(jù)庫,當(dāng)然易稠,名字?jǐn)?shù)據(jù)庫的名字可以任意起包蓝,不過一定要對應(yīng)上企量。

spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update

這兩句是省去我們建表的麻煩届巩,建好數(shù)據(jù)庫后,啟動后臺代碼腕唧,這兩行配置就會自動在數(shù)據(jù)庫中創(chuàng)建表瘾英,前提是我們必須把實(shí)體類Contract已經(jīng)寫好了。

現(xiàn)在我們來看前端代碼結(jié)構(gòu):


前端代碼結(jié)構(gòu).png

index.js

import Vue from 'vue'
import Router from 'vue-router'

import Dashboard from '@/components/Dashboard'
import Main from '@/components/Main'



Vue.use(Router)

let routes = [{
    path:'/',
    component: Main,
    hidden: true,
    children: [{
        path: '/',
        component:Dashboard,
        name:'首頁'
    }]
}]

import {
    SystemRouter
} from './system'

for (let i in SystemRouter){
    routes.push(SystemRouter[i])
}

const router = new Router({
    routes: routes
})

export default router;

system.js

import Main from '@/components/Main'
import Contract from '@/components/system/Contract'

const SystemRouter = [{
    path: '/system',
    name: '系統(tǒng)中心',
    component: Main,
    iconCls: 'fa fa-address-card',
    children: [{
        path: '/system/contract',
        component: Contract,
        name: '聯(lián)系人管理'
    }]
}]

export {
    SystemRouter
}

componments/system/Contract.vue

<template>
    <section>
        <el-col :span="24" class="toolbar" style="padding-bottom: 0px; height: 100px;">
            <el-button size="mini" @click="save">添加聯(lián)系人</el-button>
        </el-col>

        <el-table :data="rows" highlight-current-row stripe border v-loading="listLoading" style="width: 100%;">
            <el-table-column prop="name" :show-overflow-tooltip="true" label="姓名" min-width="110" sortable="sortable" />
            <el-table-column prop="sex" :show-overflow-tooltip="true" label="性別" min-width="170" sortable="sortable" />
            <el-table-column prop="phone" :show-overflow-tooltip="true" label="手機(jī)號" min-width="170" sortable="sortable" />
            <el-table-column prop="idCard" :show-overflow-tooltip="true" label="身份證號" min-width="170" sortable="sortable" />
            <el-table-column prop="address" :show-overflow-tooltip="true" label="住址" min-width="170" sortable="sortable" />
            <el-table-column label="操作" width="180" align="center" fixed="right">
                <template slot-scope="scope">
                    <el-button size="small" @click="edit(scope.row)">修改</el-button>
                    <el-button size="small" type="danger" @click="remove(scope.row)">刪除</el-button>
                </template>
            </el-table-column>
        </el-table>

        <el-dialog :title="title" width="80%" :visible.sync="formVisible" :close-on-click-modal="false">
            <el-form :model="form" label-width="120px" ref="form">
                <el-form-item label="姓名">
                    <el-input v-model="form.name" auto-complete="off" />
                </el-form-item>
                <el-form-item label="姓別">
                    <el-input v-model="form.sex" auto-complete="off" />
                </el-form-item>
                <el-form-item label="手機(jī)號">
                    <el-input v-model="form.phone" auto-complete="off" />
                </el-form-item>
                <el-form-item label="身份證號">
                    <el-input v-model="form.idCard" auto-complete="off" />
                </el-form-item>
                <el-form-item label="住址">
                    <el-input v-model="form.address" auto-complete="off" />
                </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
                <el-button @click.native="formVisible = false">取消</el-button>
                <el-button type="success" @click="submit" :loading="loading">通過</el-button>
            </div>
        </el-dialog>
    </section>
</template>
<script>
    import {
        Save,
        GetAll,
        Remove
    } from '@/api/main/contract'

    let data = () => {
        return {
            formVisible: false,
            loading: false,
            form: {},
            rows: [],
            listLoading: false,
            title: ''
        }
    }

    let save = function() {
        this.title = "添加聯(lián)系人";
        this.formVisible = true
        this.loading = false
        this.form = {}
        this.getRows()
    }

    let submit = function() {
        Save(this.form).catch(() => this.listLoading = false).then(res => {
            this.formVisible = false
            if(!res.data.success) {
                this.$message({
                    type: 'error',
                    message: res.data.message
                })
                return
            }
            this.$message({
                type: 'success',
                message: '添加成功!'
            })
            this.getRows()
        })
    }

    let getRows = function() {
        this.listLoading = true
        GetAll().then(res => {
            this.rows = res.data
            this.listLoading = false
        })
    }

    let edit = function(row) {
        this.formVisible = true;
        this.title = "編輯";
        this.form = Object.assign({}, row);
    }

    let remove = function(row) {
        this.$confirm('此操作將永久刪除該數(shù)據(jù), 是否繼續(xù)?', '提示', {
            confirmButtonText: '確定',
            cancelButtonText: '取消',
            type: 'warning'
        }).then(() => {
            if(this.listLoading)
                return
            this.listLoading = true
            Remove(row.id).catch(() => this.listLoading = false).then(res => {
                this.listLoading = false
                if(!res.data.success) {
                    this.$message({
                        type: 'error',
                        message: res.data.message
                    })
                    return
                }
                this.$message({
                    type: 'success',
                    message: '刪除成功!'
                })
                this.getRows()
            })
        }).catch(() => {});
    }

    export default {
        data: data,
        methods: {
            getRows: getRows,
            save: save,
            submit: submit,
            edit: edit,
            remove: remove
        },
        mounted: function() {
            this.getRows();
        }
    }
</script>
<style>

</style>

api/main/contract.js

import axios from 'axios';

let base = '/api/contract'

export const Save = params => {
  return axios.post(base + '/save', params);
}

export const GetAll = params => {
  return axios.post(base + '/findAll', params);
}

export const Remove = params => {
  return axios.get(base + '/remove/' + params);
}

將前端代碼跑起來阳啥,整個(gè)系統(tǒng)就完成了,可以去試試奧斩狱。
我這里寫的比較粗卷拘,基本的代碼講解都沒有,但是都是一些很簡單很簡單的東西污筷,去了解了解就可以了。前端都是用的現(xiàn)成的組件陆蟆,不了解的可以去看看Element UI惋增,后端增刪改查操作也都是用的JPA提供的簡單封裝好的方法,不了解的可以去查查。
完整代碼克隆地址:https://code.aliyun.com/zouzoutingting/console.git

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末壶冒,一起剝皮案震驚了整個(gè)濱河市截歉,隨后出現(xiàn)的幾起案子瘪松,更是在濱河造成了極大的恐慌,老刑警劉巖毫胜,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件口渔,死亡現(xiàn)場離奇詭異,居然都是意外死亡攻礼,警方通過查閱死者的電腦和手機(jī)栗柒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來太伊,“玉大人僚焦,你說我怎么就攤上這事》急” “怎么了名扛?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我惹苗,道長耸峭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任院究,我火速辦了婚禮本涕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘样漆。我一直安慰自己晦闰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布跪妥。 她就那樣靜靜地躺著眉撵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鄙皇。 梳的紋絲不亂的頭發(fā)上仰挣,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機(jī)與錄音错蝴,去河邊找鬼颓芭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛官紫,可吹牛的內(nèi)容都是我干的州藕。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼锈死!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起其屏,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤漫玄,失蹤者是張志新(化名)和其女友劉穎压彭,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體汗盘,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡隐孽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了踢俄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晴及。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡虑稼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出歌懒,到底是詐尸還是另有隱情溯壶,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布验烧,位于F島的核電站钾虐,受9級特大地震影響笋庄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜菌仁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一济丘、第九天 我趴在偏房一處隱蔽的房頂上張望洽蛀。 院中可真熱鬧,春花似錦峡碉、人聲如沸驮审。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至咕宿,卻和暖如春颂碧,著一層夾襖步出監(jiān)牢的瞬間载城,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工川队, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留睬澡,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓斗躏,卻偏偏與公主長得像昔脯,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子云稚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345