1. 声明一下:自己也是一知半解,并不是完全理解,写这篇博客,一是为了帮大家一块入门,共同进步,二也是为了让自己有所进步,下面代码有冗余现象正常,有不规范的地方也是正常,入门阶段,代码能跑,心满意足。
2. 代码摆在这了,在我这里是可以运行的,不然我也不会发出来,看的时候仔细看,需要注意的地方我都标出来了,只要注意,完全没问题的,报错,是你自己写错代码了,不要埋怨自己的机子不行、环境不行什么的。从自身出发,寻找自己的问题,同时也欢迎大佬斧正。
3. 进入正题。首先看下目录结构,我把需要注意的用红色码标注了,没必要看的就用黄色的挡住了。这次主要操作的是work这个数据表
4. 每一个文件都要注意下有没有注解。就是以@开头的东西
5. 这里需要注意的是,所有的目录,都是在启动项目录的下层的。这个是必须在它下层的(同级可能也可以,没试过)。
先实在跟application.properties文件相同的位置新键一个application.yml文件(直接新键文件,然后改后缀就行,这个没必要讲,常识)。
8080是端口号,我是默认的,没有修改,改了的话就用自己的。
下面url地方有需要改的。
url里面有个yhy?,yhy是我的数据库名,这个改成自己的,问号要保留。
其他地方都不需要改,包括dirver-class-name。
server:
port: 8080
servlet:
context-path:
spring:
datasource:
username: root
password: root
url: jdbc:mysql://localhost:3306/yhy?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
这里的代码没什么好说的,就是根据数据表里面的字段名,封装起来,然后写getter、setter方法。我把需要导的包页写上了,不合适的可以对照一下,写这个报错的话,一定别把包导错了。
必须要说的一点是,必须要写注解!!!实体里面我写了三个注解
package com.example.stu;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
//work是我的表名,到时候替换成自己的就可以了
@Entity(name = "work")
@Table(name = "work")//这个貌似可以不写,到时候试试,不行就删了,
public class Work {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)//规定默认的id
private String id;//id
private String name;//姓名
private String cla;//班级
//这里我还省略了很多的字段名,下面代码碰到字段名我会指出
//写getter/setter方法
因为大部分的方法都来自继承的对象,所以基本用不到sql语句了,用sql语句纯粹是无奈之举,实在不会了才用sql语句。而且在这里使用sql语句,就失去了springBoot的意义了。(个人理解,大佬指点批评,虚心接受)
package com.example.dao;
import org.springframework.data.domain.Pageable;
import java.util.List;
import java.util.Map;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository;
import com.example.stu.Work;
public interface WorkDAO extends PagingAndSortingRepository<Work, String>,JpaSpecificationExecutor<Work>{
//查询所有数据的方法
@Query("from work w order by w.id asc")
List<Work> findAll();//findAll方法有内置的,这里写sql语句是刚开始学的时候用的。而且这里用的sql语句已经不是原生的sql语句了,原生的sql语句写法见表连接方法
//模糊查询 findBy**Like*(参数)是内置的方法,**代表字段名,详细的介绍我有一篇单独的博客,可以参考一下
List<Work> findByidLike(String id);
//通过tell字段名进行精确查询,效果跟下面的sql相同
//原生sql:select * from work where tell = ?
List<Work> findBytell(String tell);
//修改,因为要数据回显,所以要有一个单独的方法查询,返回值是Work,根据id查询
Work findByid(String id);
//表连接,实属无奈,不会,只能用sql语句了,还是用原生的。在最后加上那个,就是代表的原生sql cla是我的另一个表
@Query(value="select * from work w join cla c on w.cla = c.cid",nativeQuery = true)
List<Map> findAllData();//表连接返回值是list
//分页,这里的findAll参数跟上面的findAll参数不同,所以问题不大。返回值是page的findAll方法也是有内置的,但是没用过,当时时间不充足,没时间试,就写了sql语句
//@Query("from work w order by w.id asc")
Page<Work> findAll(Pageable page);
//分页表连接
@Query(value="select * from work w join cla c on w.cla = c.cid",nativeQuery = true)
Page<List<Map>> findAllMap(Pageable page);
}
## **继承DAO service部分代码**
这里有两个注解,记得写上。
其他没什么要注意的了
```java
package com.example.service;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import com.example.dao.WorkDAO;
import com.example.stu.Work;
@Service
public class WorkService {
@Autowired
//查询全部
private WorkDAO workDAO;
public List<Work> findAll(){
return workDAO.findAll();
}
public List<Map> findAllData(){
return workDAO.findAllData();
}
//根据id查询
public Work findId(String id){
return workDAO.findByid(id);
}
//模糊查询
public List<Work> findByIdLike(String id){
return workDAO.findByidLike(id);
}
//添加
public void save(Work work) {
workDAO.save(work);
}
//验证手机号唯一
public List<Work> findBytell(String tell){
return workDAO.findBytell(tell);
}
//删除
public void del(Work work) {
workDAO.delete(work);
}
//分页
public Page<Work> findpage(Pageable page){
return workDAO.findAll(page);
}
//分页表连接
public Page<List<Map>> findAllMap(Pageable page){
return workDAO.findAllMap(page);
}
}
这里我把导入的包先单独放一块了,分页要导入的包自己注意下,别导错了
package com.example.controller;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;//分页
import org.springframework.data.domain.PageRequest;//分页
import org.springframework.data.domain.Pageable;//分页
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.example.service.ClaService;
import com.example.service.WorkService;
import com.example.stu.Cla;
import com.example.stu.Work;
@Controller
@RequestMapping("work")//应该可以解释为给以下内容起个名字
public class WorkController {
@Autowired
private WorkService workService;
@Autowired
private ClaService claService;
/**
* @param 首页模块
* @return 首页
*/
@RequestMapping(value = "index")//给当前的方法起名字,调用的时候是work/index
//这里是向html首页映射值的部分,还是映射了两个值,映射一个的话就省略一块就行
public String index(Model model) {//model就是向模板映射的方法
//传work
List<Work> data = workService.findAll();
model.addAttribute("data", data);//向模板映射值
//传cla,这里是传的另一个表的数据,需要在同目录下新建entiy、dao、service什么的,我就不列出来了,下面的方法我没有写出来
List<Cla> list = claService.findAll();
model.addAttribute("list", list);
return "/workIndex";//返回值是返回到首页,workindex是首页文件名,没有后缀是我提前在其他地方改好了,你没有改的话就写workindex.html。在stringBoot中,貌似不能直接打开html/jsp文件,只能通过controller中的方法来调用html/jsp文件。所以说在这要打开html文件的话用localhost:8080/work/index就可以了。index是注解中的index
}
/**
* @param 表连接向模板映射值
*/
//这个跟上一个功能相同,都是向首页映射值,不过下面的是用表连接写,只能用其中一个,首页中我是接收的这个映射的值。(boss规定要用表连接,而且表连接方便后期修改)
@RequestMapping(value = "indexAll")
public String indexAll(Model model) {
List<Map> list = workService.findAllData();
model.addAttribute("data", list);
return "/workIndex";
}
/**
* @prarm 添加模块
* @return 重定向返回首页模块
*/
//添加主体
@RequestMapping("add")
public String add(Model model) {
//这里的这部分是向添加页面映射可选的班级有哪些,没有添加功能
List<Cla> list = new ArrayList<Cla>();
list = claService.findAll();
model.addAttribute("data", list);
return "/workAdd";
}
//添加功能在以下代码块实现
@RequestMapping("save")
public String save(HttpServletRequest req,Model model) {
//获取值
String id = req.getParameter("id");
String ho[] = req.getParameterValues("hobby");//接收过来是数组的形式,然后用下面注释的那句转字符串格式,如果接收的是字符串,就没必要转,算是个例子
//String province = StringUtils.join(pro,"|");
String hobby = StringUtils.join(ho,"、");
String intro = req.getParameter("intro");
//赋值,这里字段名太多了,我删了几个,跟上面的对不起来页正常
Work work = new Work();
work.setId(id);
work.setTell(tell);
//调用添加方法
workService.save(work);//上面的基本都是废话,接收值和设置值的,只有这一步才是真正的实现添加功能
//返回首页模块
return "redirect:/work/indexAll";//redirect是重定向,不需要也不能导包,导了就报错。
}
/**
* @param 验证手机号唯一
* @return boolean
*/
//规定的功能,没需求的话完全可以不写,就当是一个精确查询的模块
@RequestMapping("tell")
@ResponseBody
public boolean tell(HttpServletRequest req) {
String tell = req.getParameter("tell");
List<Work> list = new ArrayList<Work>();
list = workService.findBytell(tell);
if(list.size()>0) {
//>0查询到数据,不可以注册
return false;
}else {
return true;
}
}
/**
* @param 删除模块
* @return 重定向返回主页模块
*/
//最喜欢删除模块了,简单直接,只需要传一个id就可以根据id进行删除,根据其他删除也类似
@RequestMapping("del")
public String del(HttpServletRequest req) {
String id[] = req.getParameterValues("id");
for(int i=0; i<id.length; i++) {
Work work = new Work();
work.setId(id[i]);
workService.del(work);
}
return "redirect:/work/indexAll";
}
/**
* @param 修改模块
* @return 重定向返回主页模块
*/
//获取需要修改的那条的信息,映射的到修改页面,然后调用添加方法。添加方法规定id将新内容替换原来的内容,不规定id,就是普通的添加,规定新的id,也是添加
//向模板映射值后,点击添加,调用save方法,进行添加。修改的方法跟添加共用一个save方法。一定要注意修改时id的接收情况,不然有可能会成添加
@RequestMapping("findId")
public String findId(HttpServletRequest req,Model model) {
String id =req.getParameter("id");
Work work = new Work();
work = workService.findId(id);
model.addAttribute("data",work);
List<Cla> list = new ArrayList<Cla>();
list = claService.findAll();
model.addAttribute("list", list);
return "/workExis";
}
//分页
//分页是vue里面的,我给了他一个单独的index页面,因为这个不懂,所以就不写太多注释了
//调用首页
@RequestMapping("VueIndex")
public String VueIndex() {
return "/VueWorkIndex";//这个是分页的首页文件名
}
@RequestMapping("VuePage")
@ResponseBody
public Page<List<Map>> VuePage(HttpServletRequest req){//这里一定要注意导的包是哪个;返回值是page类型的,里面的list
//NowPage=0;
Integer NowPage = Integer.parseInt(req.getParameter("page"));//获取当前页
Sort sort = null;
sort = new Sort(Sort.Direction.DESC,"id");//根据id进行排序
Pageable Page = PageRequest.of(NowPage-1, 4, sort);//每四条数据为一页,这里为什么-1我也不知道,是自己试出来的,不-1出问题
Page<List<Map>> data = workService.findAllMap(Page);
return data;
}
}
这里的前端代码包含了全选效果,没必要的字段名都删了,表格对齐情况可能有点问题,自己使用的时候小细节修改一下
<html>
<head>
<meta charset="UTF-8">
<title>Insert title heretitle>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js">
script>
<script type="text/javascript">
$(function() {
var i=false;
//全选操作
$("#all").on("click",function(){
if(i==false){
$("input[name='id']").prop("checked",true);
i=true;
}else{
$("input[name='id']").prop("checked",false);
i=false;
}
});
//反选操作
$("#Rev").on("click",function(){
$("[type=checkbox]:checkbox").each(function() {
this.checked = !this.checked;
i=!i;
});
});
//全不选操作
$("#allNot").on("click",function(){
$("input[name='id']").prop("checked",false);
i=false;
});
});
//批量删除判断数据量
function del() {
var j=0;
$("[type=checkbox]:checkbox").each(function() {
if(this.checked ==true ){
j++;
}
});
if(j>=1){
return true;
}else{
alert("至少选择一项内容");
return false;
}
}
script>
head>
<body>
<br />
<form action="del">
<table border="1" width="990px" cellspacing="0" cellpadding="5px" align="center" style="transparent;background-color:rgba(199,237,204,0.45)">
<tr>
<td colspan="9">信息添加: <a href="/work/add"><input type="button" value="添加"/>a>
td>
tr>
<tr>
<td colspan="9">批量操作:
<input type="submit" onclick="return del()" value="批量删除">
td>
tr>
<tr>
<th width="60px">编号th>
<th width="120px">账号th>
<th width="350px">简介th>
<th width="120px">操作th>
tr>
<tr th:each="work,loopStatus:${data}">
<td align="center">
<span th:text="${loopStatus.count}" >span>
<span>span><input type="checkbox" name="id" th:value="${work.id}"> span>
td>
<td align="center" th:text="${work.province+','+work.city+','+work.area}">td>
<td align="center" th:text="${work.hobby}">td>
<td align="center" th:text="${work.intro}">td>
<td align="center">
<a th:href="@{findId(id=${work.id})}">
<input type="button" value="修改" />a>
<a th:href="@{del(id=${work.id})}">
<input type="button" value="删除" />a>
td>
tr>
table>
form>
body>
html>
有判断唯一性的(ajax)、省市级三级联动效果(自己百度的代码,直接复制上了)
<html>
<head>
<meta charset="UTF-8">
<title>Insert title heretitle>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js">
script>
<script type="text/javascript">
$(function () {
//AJAX判断手机号唯一性
$("#tell").keyup(function() {
//获取输入的tell值
//alert(2);
var tell = $("#tell").val();
//alert(tell);
$.post("/work/tell",{tell:tell},function(data){
//alert(data);
if(tell != null){
//接收到的data为Boolean型
if(data){
$("#text").html(" 可以注册");
$("#submit").attr('disabled',false);
}else{
$("#text").html(" 重复,禁止注册");
$("#submit").attr('disabled',true);
}
}
});
});
});
script>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js">script>
<script src="https://cdn.bootcss.com/distpicker/2.0.1/distpicker.js">script>
head>
<body>
<br /><br />
<table border="1" cellspacing="0" cellpadding="5px" width="700px" align="center" >
<tr>
<td>
<form action="/work/save">
手机号:<input type="text" id="tell" name="tell"><span id="text">span><br /><br />
姓 名:<input type="text" name="name"><br /><br />
班 级:
<select name="cla" >
<option th:each="cla:${data}" th:value="${cla.cid}" th:text="${cla.cname}">option>
select><br /><br />
性 别:<input type="radio" name="sex" value="男">男 <input type="radio" name="sex" value="女">女<br /><br />
<div data-toggle="distpicker" data-autoselect="3">
地 址:
<select name="province">select>
<select name="city">select>
<select name="area">select>
div><br /><br />
爱 好:<input type="checkbox" value="代码" name="hobby">代码
<input type="checkbox" value="游戏" name="hobby">游戏
<input type="checkbox" value="音乐" name="hobby">音乐 <br /><br />
简 介:<textarea rows="5" cols="35" name="intro" style=resize:none;>textarea><br /><br />
<input type="submit" value="提交"><br />
form>
td>
tr>
table>
body>
html>
没有代码,直接在首页点删除,就直接删除了,没有什么多余的花里胡哨的代码
最烦的就是修改页了,代码多,花里胡哨的
实现效果:验证手机号是否唯一,文本域数据回显、单选框数据回显
bug:多选框、省市级三级联动(有自带的默认显示)没能实现数据回显;手机号部分,输入数据后,清空数据会提示可以注册/不能注册
<html>
<head>
<meta charset="UTF-8">
<title>Insert title heretitle>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js">
script>
<script type="text/javascript">
$(function () {
//AJAX判断手机号唯一性
$("#tell").keyup(function() {
//获取输入的tell值
//alert(2);
var tell = $("#tell").val();//获取输入的tell
//alert(tell);
//将获取的tell传给controller,看返回值
$.post("/work/tell",{tell:tell},function(data){
//alert(data);
if(tell != null){
if(data){//接收到的data为Boolean型
$("#text").html(" 可以注册");
$("#submit").attr('disabled',false);
}else{
$("#text").html(" 重复,禁止注册");
$("#submit").attr('disabled',true);
}
}
});
});
});
script>
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js">script>
<script src="https://cdn.bootcss.com/distpicker/2.0.1/distpicker.js">script>
head>
<body>
<br /><br />
<table border="1" cellspacing="0" cellpadding="5px" width="700px" align="center">
<tr>
<td>
<form action="/work/save" method="post" th:object="${data}">
手机号:<input type="text" id="tell" name="tell" th:value="*{tell}" placeholder="十个数以内"><span id="text">span><br /><br />
<input type="hidden" name="id" th:value="*{id}">
姓 名:<input type="text" name="name" th:value="*{name}"><br /><br />
班 级:
<select name="cla" >
<option th:each="cla:${list}" th:attr="selected=${data.cla==cla.cid?true:selected}" th:value="${cla.cid}" th:text="${cla.cname}" >option>
select>
<br /><br />
性 别:
<input type="radio" name="sex" value="男" th:attr="checked=${data.getSex()=='男'?true:false}">男
<input type="radio" name="sex" value="女" th:attr="checked=${data.getSex()=='女'?true:false}">女<br /><br />
<div data-toggle="distpicker" data-autoselect="3">
地 址:
<select name="province" th:text="${province}">select>
<select name="city" th:text="*{city}">select>
<select name="area" th:text="*{area}">select>
div><br /><br />
爱 好:
代码<input type="checkbox" value="代码" name="hobby">
游戏<input type="checkbox" value="游戏" name="hobby">
音乐<input type="checkbox" value="音乐" name="hobby"> <br /><br />
简 介:<textarea rows="5" cols="35" th:text="${data.intro}" name="intro" style=resize:none; >textarea><br /><br />
<input type="submit" value="提交">
form>
td>
tr>
table>
body>
html>
分页index
<html>
<head>
<meta charset="UTF-8">
<title>Insert title heretitle>
<script src="https://cdn.staticfile.org/vue/2.2.2/vue.min.js">script>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js">script>
<style type="text/css">
.page-bar{margin:40px auto;margin-top: 150px;}
ul,li{margin: 0px;padding: 0px;}
li{list-style: none}
.page-bar li:first-child>a {margin-left: 0px}
.page-bar a{border: 1px solid #ddd;text-decoration: none;position: relative;float: left;padding: 6px 12px;margin-left: -1px;line-height: 1.42857143;color: #5D6062;cursor: pointer;margin-right: 20px;}
.page-bar a:hover{background-color: #eee;}
.page-bar a.banclick{cursor:not-allowed;}
.page-bar .active a{color: #fff;cursor: default;background-color: #E96463;border-color: #E96463;}
.page-bar i{font-style:normal;color: #d44950;margin: 0px 4px;font-size: 12px;}
style>
head>
<body>
<br />
<table border="1" width="990px" cellspacing="0" cellpadding="5px"
align="center" style="background-color: rgba(199, 237, 204, 0.45)"
id="app">
<tr>
<td colspan="10">
<div class="page-bar">
<ul>
<li v-if="cur>1"><a v-on:click="cur--,pageClick()">上一页a>li>
<li v-if="cur==1"><a class="banclick">上一页a>li>
<li v-for="index in indexs" v-bind:class="{ 'active': cur == index}">
<a v-on:click="btnClick(index)">{{ index }}a>
li>
<li v-if="cur!=all"><a v-on:click="cur++,pageClick()">下一页a>li>
<li v-if="cur == all"><a class="banclick">下一页a>li>
<li><a>共<i>{{all}}i>页a>li>
ul>
div>
td>
tr>
<tr>
<th width="60px">编号th>
<th width="120px">账号th>
<th width="90px">姓名th>
<th width="240px" colspan="2">操作th>
tr>
<tr v-for="(site,key) in sites">
<td align="center">{{key+1}}td>
<td align="center">{{site.tell}}td>
<td align="center">{{site.name}}td>
<td align="center">{{site.cname}}td>ype="button"
value="删除">a>td>
<td><a v-on:click="edit(site.id)"><input type="button"
value="修改">a>td>
tr>
table>
<script>
var vm = new Vue({
el: '#app',
data:{
sites:[],
all:6,
cur:1,
totalPage:0
},
mounted(){
this.dataListFn(1);
},
methods:{
dataListFn:function(index){
var page = index;
//alert(page);
$.post("/work/VuePage",{page:page},function(data){
//alert(12);
vm.sites=[];
//var datalist=data.contene;
//alert(JSON.stringify(data.content));//接收数据成功
var len = data.content.length;
for(var i=0;i<len;i++){
vm.sites.push(data.content[i]);
}
vm.all = data.totalPages;
vm.cur = data.number+1;
vm.totalPage = data.numberOfElements;
});
},
//要注意其他方法写的位置,位置不合适会报错not find,我也是试了很多地方才找到这里的
del:function(id,key){
$.post("/work/VueDel",{id,id},function(data){
if(data==1){
vm.sites.splice(key,1);
}
});
},
edit:function(id,key){
window.location.href="/work/VueEdit?id="+id;
},
add:function(){
window.location.href="/work/add";
},
//分页
btnClick: function(data){//页码点击事件
if(data != this.cur){
this.cur = data
}
//根据点击页数请求数据
this.dataListFn(this.cur.toString());
},
pageClick: function(){
//根据点击页数请求数据
this.dataListFn(this.cur.toString());
}
},
computed: {
//分页
indexs: function(){
var left = 1;
var right = this.all;
var ar = [];
if(this.all>= 5){
if(this.cur > 3 && this.cur < this.all-2){
left = this.cur - 2
right = this.cur + 2
}else{
if(this.cur<=3){
left = 1
right = 5
}else{
right = this.all
left = this.all -4
}
}
}
while (left <= right){
ar.push(left)
left ++
}
return ar
}
},
});
script>
body>
html>