完整的 Spring Boot 应用程序示例

好的,我将为你提供一个完整的 Spring Boot 应用程序示例,其中包括了使用 Spring Data JPA 进行数据库操作、使用 Thymeleaf 作为模板引擎来渲染 HTML 页面,并集成 Vue.js 和 Element UI 用于前端界面展示和交互。

我们将创建一个简单的应用,包含以下几个部分:

  1. Spring Boot 后端服务
  2. Thymeleaf 渲染 HTML 页面
  3. Vue.js + Element UI 的前端界面

1. 创建 Spring Boot 项目

首先,我们需要创建一个 Spring Boot 项目。你可以使用 Spring Initializr 快速生成一个项目骨架,或者手动创建一个项目。这里我们假设你已经有一个基本的 Spring Boot 项目结构。

添加依赖

pom.xml 文件中添加必要的依赖:

<dependencies>
    <!-- Spring Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- Spring Data JPA -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- MySQL Driver -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>

    <!-- Thymeleaf -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

    <!-- Vue.js and Element UI (通过 CDN 引入) -->
    <!-- 不需要在 pom.xml 中添加 -->

    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <!-- Dev tools for hot reloading -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>

    <!-- Test dependencies -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

<properties>
    <spring-boot.version>3.1.2</spring-boot.version>
</properties>

2. 配置数据库连接

application.properties 文件中配置数据库连接:

spring.datasource.url=jdbc:mysql://localhost:3306/your_database_name
spring.datasource.username=your_username
spring.datasource.password=your_password
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

3. 创建实体类

创建一个 AnchorInfo 实体类:

import javax.persistence.*;

@Entity
@Table(name = "anchor_info")
public class AnchorInfo {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "anchor_id")
    private String anchorId;

    @Column(name = "reward_service_fee")
    private double rewardServiceFee;

    @Column(name = "portal_service_fee")
    private double portalServiceFee;

    @Column(name = "task_reward_service_fee")
    private double taskRewardServiceFee;

    @Column(name = "bulletin_play_service_fee")
    private double bulletinPlayServiceFee;

    @Column(name = "paid_queue_service_fee")
    private double paidQueueServiceFee;

    @Column(name = "vip_subscription_fee")
    private double vipSubscriptionFee;

    @Column(name = "vip_subscription_refund")
    private double vipSubscriptionRefund;

    @Column(name = "vip_card_service_fee")
    private double vipCardServiceFee;

    @Column(name = "guest_connect_guest_fee")
    private double guestConnectGuestFee;

    @Column(name = "guest_connect_host_fee")
    private double guestConnectHostFee;

    @Column(name = "gifts_to_promote_broadcast")
    private double giftsToPromoteBroadcast;

    @Column(name = "bundle_sale_service_fee")
    private double bundleSaleServiceFee;

    @Column(name = "service_fee_refund")
    private double serviceFeeRefund;

    @Column(name = "individual_unconventional_recharge_deduction")
    private double individualUnconventionalRechargeDeduction;

    @Column(name = "individual_task_deduction")
    private double individualTaskDeduction;

    @Column(name = "guild_adjustment")
    private double guildAdjustment;

    @Column(name = "new_recruit_task_reward")
    private double newRecruitTaskReward;

    @Column(name = "new_recruit_cheat_appeal_compensation")
    private double newRecruitCheatAppealCompensation;

    @Column(name = "flow_task_cheat_appeal_compensation")
    private double flowTaskCheatAppealCompensation;

    @Column(name = "new_process_broadcast_task")
    private double newProcessBroadcastTask;

    @Column(name = "new_process_broadcast_cheat_appeal_compensation")
    private double newProcessBroadcastCheatAppealCompensation;

    @Column(name = "new_process_revenue_upgrade_task_a")
    private double newProcessRevenueUpgradeTaskA;

    @Column(name = "new_process_revenue_upgrade_task_b")
    private double newProcessRevenueUpgradeTaskB;

    @Column(name = "new_process_revenue_upgrade_cheat_appeal_compensation_b")
    private double newProcessRevenueUpgradeCheatAppealCompensationB;

    @Column(name = "new_process_revenue_breakthrough_task")
    private double newProcessRevenueBreakthroughTask;

    @Column(name = "new_process_revenue_breakthrough_cheat_appeal_compensation")
    private double newProcessRevenueBreakthroughCheatAppealCompensation;

    @Column(name = "new_process_high_quality_content_broadcast_task")
    private double newProcessHighQualityContentBroadcastTask;

    @Column(name = "serious_violation_deduction")
    private double seriousViolationDeduction;

    @Column(name = "high_quality_content_anchor")
    private double highQualityContentAnchor;

    @Column(name = "guild_income")
    private double guildIncome;

    @Column(name = "repeat_count")
    private int repeatCount;

    // Getters and Setters
    public Long getId() {
        return id;
    }

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

    public String getAnchorId() {
        return anchorId;
    }

    public void setAnchorId(String anchorId) {
        this.anchorId = anchorId;
    }

    // ... (省略其他字段的getter和setter方法)
}

4. 创建 Repository

创建一个 AnchorInfoRepository 接口继承 JpaRepository

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

@Repository
public interface AnchorInfoRepository extends JpaRepository<AnchorInfo, Long> {
}

5. 创建 Service

创建一个 AnchorInfoService 类:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class AnchorInfoService {

    @Autowired
    private AnchorInfoRepository anchorInfoRepository;

    public List<AnchorInfo> getAllAnchors() {
        return anchorInfoRepository.findAll();
    }

    public AnchorInfo getAnchorById(Long id) {
        return anchorInfoRepository.findById(id).orElse(null);
    }

    public AnchorInfo createAnchor(AnchorInfo anchorInfo) {
        return anchorInfoRepository.save(anchorInfo);
    }

    public AnchorInfo updateAnchor(AnchorInfo anchorInfo) {
        return anchorInfoRepository.save(anchorInfo);
    }

    public void deleteAnchor(Long id) {
        anchorInfoRepository.deleteById(id);
    }
}

6. 创建 Controller

创建一个 AnchorInfoController 类:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/anchors")
public class AnchorInfoController {

    @Autowired
    private AnchorInfoService anchorInfoService;

    @GetMapping
    public List<AnchorInfo> getAllAnchors() {
        return anchorInfoService.getAllAnchors();
    }

    @GetMapping("/{id}")
    public AnchorInfo getAnchorById(@PathVariable Long id) {
        return anchorInfoService.getAnchorById(id);
    }

    @PostMapping
    public AnchorInfo createAnchor(@RequestBody AnchorInfo anchorInfo) {
        return anchorInfoService.createAnchor(anchorInfo);
    }

    @PutMapping("/{id}")
    public AnchorInfo updateAnchor(@PathVariable Long id, @RequestBody AnchorInfo anchorInfo) {
        anchorInfo.setId(id);
        return anchorInfoService.updateAnchor(anchorInfo);
    }

    @DeleteMapping("/{id}")
    public void deleteAnchor(@PathVariable Long id) {
        anchorInfoService.deleteAnchor(id);
    }
}

7. 创建 Thymeleaf 模板

src/main/resources/templates 目录下创建一个 anchor-list.html 文件:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Anchor List</title>
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
</head>
<body>
<div id="app">
    <el-table :data="anchors" style="width: 100%">
        <el-table-column prop="anchorId" label="主播ID" width="180"></el-table-column>
        <el-table-column prop="rewardServiceFee" label="打赏主播服务费"></el-table-column>
        <el-table-column prop="portalServiceFee" label="传送门服务费"></el-table-column>
        <el-table-column prop="taskRewardServiceFee" label="打赏主播任务服务费"></el-table-column>
        <el-table-column prop="bulletinPlayServiceFee" label="弹幕玩法服务费"></el-table-column>
        <el-table-column prop="paidQueueServiceFee" label="付费连线队列服务费"></el-table-column>
        <el-table-column prop="vipSubscriptionFee" label="会员订阅服务费"></el-table-column>
        <el-table-column prop="vipSubscriptionRefund" label="会员订阅服务费退款"></el-table-column>
        <el-table-column prop="vipCardServiceFee" label="会员卡服务费"></el-table-column>
        <el-table-column prop="guestConnectGuestFee" label="嘉宾连线嘉宾服务费"></el-table-column>
        <el-table-column prop="guestConnectHostFee" label="嘉宾连线主播服务费"></el-table-column>
        <el-table-column prop="giftsToPromoteBroadcast" label="礼物打赏促开播"></el-table-column>
        <el-table-column prop="bundleSaleServiceFee" label="套装售卖服务费"></el-table-column>
        <el-table-column prop="serviceFeeRefund" label="服务费退款"></el-table-column>
        <el-table-column prop="individualUnconventionalRechargeDeduction" label="个播非常规渠道充值扣款"></el-table-column>
        <el-table-column prop="individualTaskDeduction" label="个播任务扣款"></el-table-column>
        <el-table-column prop="guildAdjustment" label="公会调减"></el-table-column>
        <el-table-column prop="newRecruitTaskReward" label="拉新任务奖励"></el-table-column>
        <el-table-column prop="newRecruitCheatAppealCompensation" label="拉新任务作弊申诉补发"></el-table-column>
        <el-table-column prop="flowTaskCheatAppealCompensation" label="流水任务作弊申诉补发"></el-table-column>
        <el-table-column prop="newProcessBroadcastTask" label="新过程任务开播任务"></el-table-column>
        <el-table-column prop="newProcessBroadcastCheatAppealCompensation" label="新过程任务开播任务作弊申诉补发"></el-table-column>
        <el-table-column prop="newProcessRevenueUpgradeTaskA" label="新过程任务营收升保级任务A"></el-table-column>
        <el-table-column prop="newProcessRevenueUpgradeTaskB" label="新过程任务营收升保级任务B"></el-table-column>
        <el-table-column prop="newProcessRevenueUpgradeCheatAppealCompensationB" label="新过程任务营收升保级任务B作弊申诉补发"></el-table-column>
        <el-table-column prop="newProcessRevenueBreakthroughTask" label="新过程任务营收突破任务"></el-table-column>
        <el-table-column prop="newProcessRevenueBreakthroughCheatAppealCompensation" label="新过程任务营收突破任务作弊申诉补发"></el-table-column>
        <el-table-column prop="newProcessHighQualityContentBroadcastTask" label="新过程任务优质内容开播任务"></el-table-column>
        <el-table-column prop="seriousViolationDeduction" label="严重违规主播扣款"></el-table-column>
        <el-table-column prop="highQualityContentAnchor" label="优质内容主播"></el-table-column>
        <el-table-column prop="guildIncome" label="公会收入"></el-table-column>
        <el-table-column prop="repeatCount" label="重复次数"></el-table-column>
        <el-table-column fixed="right" label="操作" width="100">
            <template slot-scope="scope">
                <el-button @click="handleEdit(scope.$index, scope.row)" type="text" size="small">编辑</el-button>
                <el-button @click="handleDelete(scope.$index, scope.row)" type="text" size="small">删除</el-button>
            </template>
        </el-table-column>
    </el-table>
    <el-button @click="addNewAnchor">新增主播</el-button>
</div>

<script>
new Vue({
    el: '#app',
    data() {
        return {
            anchors: []
        };
    },
    mounted() {
        axios.get('/api/anchors')
            .then(response => {
                this.anchors = response.data;
            })
            .catch(error => {
                console.error("Error fetching anchors:", error);
            });
    },
    methods: {
        handleEdit(index, row) {
            // 跳转到编辑页面
            window.location.href = `/edit/${row.id}`;
        },
        handleDelete(index, row) {
            axios.delete(`/api/anchors/${row.id}`)
                .then(response => {
                    this.anchors.splice(index, 1);
                })
                .catch(error => {
                    console.error("Error deleting anchor:", error);
                });
        },
        addNewAnchor() {
            // 添加新主播
            window.location.href = '/edit';
        }
    }
});
</script>
</body>
</html>

8. 创建编辑页面

src/main/resources/templates 目录下创建一个 edit.html 文件:

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Edit Anchor</title>
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
</head>
<body>
<div id="app">
    <el-form :model="anchor" status-icon :rules="rules" ref="anchorForm" label-width="100px" class="demo-ruleForm">
        <el-form-item label="主播ID" prop="anchorId">
            <el-input v-model="anchor.anchorId" disabled></el-input>
        </el-form-item>
        <el-form-item label="打赏主播服务费" prop="rewardServiceFee">
            <el-input v-model.number="anchor.rewardServiceFee"></el-input>
        </el-form-item>
        <el-form-item label="传送门服务费" prop="portalServiceFee">
            <el-input v-model.number="anchor.portalServiceFee"></el-input>
        </el-form-item>
        <!-- 更多字段 -->
        <el-form-item>
            <el-button type="primary" @click="submitForm('anchorForm')">提交</el-button>
            <el-button @click="resetForm('anchorForm')">重置</el-button>
        </el-form-item>
    </el-form>
</div>

<script>
new Vue({
    el: '#app',
    data() {
        return {
            anchor: {
                id: null,
                anchorId: '',
                rewardServiceFee: 0,
                portalServiceFee: 0,
                // ... 其他字段
            },
            rules: {
                // 验证规则
            }
        };
    },
    created() {
        const id = this.$route.params.id;
        if (id) {
            axios.get(`/api/anchors/${id}`)
                .then(response => {
                    this.anchor = response.data;
                })
                .catch(error => {
                    console.error("Error loading anchor:", error);
                });
        }
    },
    methods: {
        submitForm(formName) {
            this.$refs[formName].validate(valid => {
                if (valid) {
                    if (this.anchor.id) {
                        axios.put(`/api/anchors/${this.anchor.id}`, this.anchor)
                            .then(response => {
                                alert('更新成功!');
                                window.location.href = '/list';
                            })
                            .catch(error => {
                                console.error("Error updating anchor:", error);
                            });
                    } else {
                        axios.post('/api/anchors', this.anchor)
                            .then(response => {
                                alert('创建成功!');
                                window.location.href = '/list';
                            })
                            .catch(error => {
                                console.error("Error creating anchor:", error);
                            });
                    }
                } else {
                    console.log('error submit!!');
                    return false;
                }
            });
        },
        resetForm(formName) {
            this.$refs[formName].resetFields();
        }
    }
});
</script>
</body>
</html>

9. 配置路由

WebSecurityConfigurerAdapter 中配置允许访问静态资源:

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/", "/list", "/edit/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
            .and()
            .logout()
            .permitAll();

        http.csrf().disable();
    }
}

10. 运行应用程序

运行应用程序并访问 http://localhost:8080/list 查看列表页面,点击“新增主播”按钮跳转到编辑页面。

以上示例提供了一个基本的框架,你可以在此基础上进一步扩展和完善。希望这对你有所帮助!

  • 11
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值