好的,我将为你提供一个完整的 Spring Boot 应用程序示例,其中包括了使用 Spring Data JPA 进行数据库操作、使用 Thymeleaf 作为模板引擎来渲染 HTML 页面,并集成 Vue.js 和 Element UI 用于前端界面展示和交互。
我们将创建一个简单的应用,包含以下几个部分:
- Spring Boot 后端服务
- Thymeleaf 渲染 HTML 页面
- 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
查看列表页面,点击“新增主播”按钮跳转到编辑页面。
以上示例提供了一个基本的框架,你可以在此基础上进一步扩展和完善。希望这对你有所帮助!