springboot简单小项目练习之增删改查-exercisePro01


(第一版:仅做了学生的增删改查)

一、项目介绍

  • 项目名称:希望小学学生管理系统

  • 项目需求:

1、学生信息的添加,删除,修改和编辑

2、需要管理的信息:

学生:学生学号,姓名,性别,班级,住址,出生日期

成绩:课程编号,学生学号,成绩

课程:课程编号,课程名称

教师:教师编号,姓名,性别,住址,出生日期

二、项目分析

1、技术分析

前端:html+css+js

后端:mysql+后台系统(springboot)

2、数据库设计

主表:

学生表——stu

名称字段名类型和长度
ididint(11)
学号stu_novarchar(255)
姓名stu_namevarchar(255)
性别genderint(11)
班级stu_classvarchar(255)
住址stu_addressvarchar(255)
出生日期stu_birthdaydatetime(0)

成绩表——grade

名称字段名类型和长度
ididint(11)
课程idcou_idint(11)
学生idstu_idint(11)
分数scoreint(11)

课程表——course

名称字段名类型和长度
ididint(11)
课程编号course_novarchar(255)
课程名称course_namevarchar(255)

教师表——teacher

名称字段名类型和长度
ididint(11)
教师编号tea_novarchar(255)
姓名tea_namevarchar(255)
性别genderint(11)
住址tea_addressvarchar(255)
出生日期tea_birthdaydatetime(0)

关联表:

学生课程关联表

名称字段名类型和长度
ididint(11)
学生idstu_idint(11)
课程idcou_idint(11)

教师课程关联表

名称字段名类型和长度
ididint(11)
教师idtea_idint(11)
课程idcou_idint(11)

三、前端

1、目录结构

image-20200821201011977

目录介绍:

css:样式修饰文件

js:这个也不知道咋个介绍法,大名叫javaScript

static:放静态资源的文件夹,图片啥的

view:放页面的文件夹

2、页面

很丑,不过不慌,以后慢慢修饰呗,功能先整上去

首页

image-20200821201300999

添加/编辑页面

image-20200821201342223

3、增删改查前台代码及解析

index.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>学生管理系统</title>
		<link rel="stylesheet" type="text/css" href="../css/index.css">
		<!--这里是我自己写的一些基础函数-->
        <script src="../js/base.js"></script>
        <!--这里引的是1.9.1的jq-->
		<script src="../js/jquery.js"></script>
        <!--这里是首页用到的一些js-->
		<script src="../js/index.js"></script>		
	</head>
	<body>
        <!--列表-->
		<div class="main">
			<table class="table" border="1">
				<tr class="tr">
					<th>序号</th>
					<th>学号</th>
					<th>姓名</th>
					<th>性别</th>
					<th>班级</th>
					<th>住址</th>
					<th>生日</th>
					<th>操作</th>
				</tr>
                <!--下面的tr都是js动态生成的-->
			</table>
		</div>
        <!--添加按钮-->
		<div class="goAdd">
			<button type="button">添加</button>
		</div>
	</body>
</html>

add.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<link rel="stylesheet" type="text/css" href="../css/add.css" />
		<script src="../js/base.js"></script>
		<script src="../js/jquery.js"></script>
		<script src="../js/add.js"></script>
		<title>添加</title>
	</head>
	<body>
		<div class="add">
			<ul>
				<li><span>学号:</span><input id = "stuNo" type="text" placeholder="学号"/></li>
				<li><span>姓名:</span><input id = "stuName" type="text" placeholder="姓名"/></li>
				<li>
					<span>性别:</span>
						<div>
							<input type="radio" name="gender" value="0"/><span></span>
							<input type="radio"name="gender" value="1"/><span></span>
						</div>	
				</li>
				<li><span>班级:</span><input id = "stuClass" type="text" placeholder="班级"/></li>
				<li><span>地址:</span><input id = "stuAddress" type="text" placeholder="地址"/></li>
				<li><span>生日:</span><input id = "stuBirthday" type="text" placeholder="生日"/></li>
			</ul>
			<ul>
				<li><button id="submit" type="button">提交</button></li>
			</ul>
		</div>
		<div class="backIndex">
			<button id="back" type="button">返回</button>
		</div>
	</body>
</html>

index.js

addLoadEvent(goAdd)//这个方法再base.js,相当于jq的$(document).ready(function(){ your code })
//跳转添加页面(古董方法,留着做个纪念)
function goAdd(){
    //getElementByXpath()也在base.js中,用的是xpath定位方法(花里胡哨)
	getElementByXpath("/html/body/div[2]/button").onclick = function(){
		window.location.href = "add.html"
	}	
}
//显示首页数据
/*
思路:
将后台数据用ajax请求到,让后js动态生成tr,将data迭代到页面上
*/
$(document).ready(function(){//页面加载完后执行
    //jq的ajax方法,开始想着自己封装Ajax了,最后发现自己菜的一批,还是jq香
	$.ajax({
		url:"http://127.0.0.1:8081/stu/findAllStu",//后台请求路径
		type:"GET",//请求方法,具体看自己后台写的是GetMapping还是PostMapping
		dataType:'json',//数据类型是json
		contentType:"application/json",//内容类型,传json就得写这个
		success:function(data){//成功时候的回调函数,凡间的话就是请求成功了,你前台要干的活儿
		 	data = dataChange(data);//将后台的数据处理一下(有些格式是不对的)
			var table = getElementByXpath("/html/body/div[1]/table");//获取table			
			var newTr = document.createElement("tr");//创建一个tr元素			
			for(var i = 0;i<data.length;i++){//迭代添加数据
                //这里将id绑定到了tr的class中,方便我删除这行tr,addClass在base.js中
				addClass(newTr,"tr del_"+data[i].id);
                //给这个tr加内容
				newTr.innerHTML = 
						'<td>'+(i+1)+'</td>'+
						'<td>'+data[i].stuNo+'</td>'+
						'<td>'+data[i].stuName+'</td>'+
						'<td>'+data[i].gender+'</td>'+
						'<td>'+data[i].stuClass+'</td>'+
						'<td>'+data[i].stuAddress+'</td>'+
						'<td>'+data[i].stuBirthday+'</td>'+
						'<td><a href="javascript:delStu('+data[i].id+')">删除</a>&nbsp;&nbsp;<a href="javascript:goModify('+data[i].id+')">编辑</a></td>';
				table.appendChild(newTr);//把这个tr添加到table中
				newTr = document.createElement("tr");//重新赋值				
			}
		},
		//异常处理
		error:function(e){
		    console.log(e);
		}
	});
});


// 数据转换(将后台数据转换一哈)
function dataChange(data){
	//创建一个新的模板
	var newData = [];
	for(var i = 0;i<data.length;i++){
		newData.push(
		{
		"id":data[i].id,
		"stuName":data[i].stuName,
		"gender":(data[i].gender == 0)?'男':'女',
		"stuNo":data[i].stuNo,
		"stuClass":data[i].stuClass,
		"stuAddress":data[i].stuAddress,
		"stuBirthday":data[i].stuBirthday.substring(0,10)//原来的日期不是很好看,这里截取一段,也可以进行转换一下
		}
		)
	}
	return newData;
}

//删除学生信息
/*
思路:
点击删除按钮,将id值传到函数里面
用ajax将id传到后台
后台根据id查出对应学生,并将学生删除标志变为1,删除时间赋值当前系统时间
*/
function delStu(stuId){
	$.ajax({
		url:"http://127.0.0.1:8081/stu/delStu",
		type:"GET",
		data:{
			"id":stuId
		},
		dataType:'json',
		timeout:10000,
		contentType:"application/json",
		success:function(data){
			//不知道是什么鬼,也不报错,但是就是不走success
		},
		error:function(e){
			$("."+"del_"+stuId).remove()
		}
	})
}

//显示编辑页面
/*
思路:首页将id传给add.html页面,
然后add.html将id截取出来传到后台获取对应学生信息显示在add.html页面上
*/
function goModify(id){
	window.location.href = "add.html?"+id;	
}





add.js


//提交学生
$(document).ready(function(){//页面加载完后执行
	$("#submit").click(function(){
		//获取学生信息
		var stuNo,stuName,stuClass,stuAddress,stuBirthday,gender;
		var id = window.location.href.split("?")[1];//截取链接中的id值
		stuNo = document.getElementById("stuNo").value;//获取学号
		stuName = document.getElementById("stuName").value;//获取名字
		stuClass = document.getElementById("stuClass").value;//获取班级
		stuAddress = document.getElementById("stuAddress").value;//获取地址
		stuBirthday = document.getElementById("stuBirthday").value;//获取生日
		gender = getElementByXpath("/html/body/div[1]/ul[1]/li[3]/div/input[1]").checked?0:1;//获取单选框值		
		//组装json
		var data = {};
		data["id"] = id;
		data["stuNo"] = stuNo;
		data["stuName"] = stuName;
		data["stuClass"] = stuClass;
		data["stuAddress"] = stuAddress;
		data["stuBirthday"] = stuBirthday;
		data["gender"] = gender;
		console.log(JSON.stringify(data))
		//ajax上传学生信息
		$.ajax({
			url:"http://127.0.0.1:8081/stu/saveStu",//请求地址
			type:"POST",//请求方法
			data:JSON.stringify(data),//将数据转换成json格式
			dataType:'json',//数据类型:json
			contentType:"application/json",//内容:json
			success:function(data){
				//不知道是什么鬼,也不报错,但是就是不走success
			},
			error:function(e){
				if(id == "undefined"){//如果没有id说明时添加
					console.log("添加成功")
				}else{//有id说明时编辑
					console.log("编辑成功")
				}
			}
		})
	
	});	
	
});
//显示编辑页面学生信息
$(document).ready(function(){
	//获取学生id
	var id = window.location.href.split("?")[1];
	//显示学生
	$.ajax({
		url:"http://127.0.0.1:8081/stu/findStu",//不说了,看上面
		type:"get",
		data:{id:id},
		dataType:'json',
		contentType:"application/json",
		success:function(data){
            //为页面赋值
			$("#stuNo").val(data.stuNo)
			$("#stuName").val(data.stuName)
			$("#stuClass").val(data.stuClass)
			$("#stuAddress").val(data.stuAddress)
			$("#stuBirthday").val((data.stuBirthday).substring(0,10))
			if(data.gender == 0){//这里用了”高级“一点的选择器,字面意思可以读懂,就不比比了
				$("input[name = 'gender'][value=0]").attr("checked",true);
			}else{
				$("input[name = 'gender'][value=1]").attr("checked",true);
			}
		},
		error:function(e){
		    console.log(e);
		}
	});
	//提交
	
})

//跳转首页页面
$(document).ready(function(){
	$("#back").click(function(){		
		window.location.href = "index.html";
	});
});

4、base.js和css

这部分就不解释了,和咱项目关系比较远了,都是些前端知识,可以看看

base.js

//文档加载函数
function addLoadEvent(func) {
    var oldonload = window.onload;
    if (typeof window.onload != 'function') {
        window.onload = func;
    } else {
        window.onload = function() {
            oldonload();
            func();
      }
    }
}
//封装xpath
function getElementByXpath(xpath){
	var element = document.evaluate(xpath,document).iterateNext();
	return element;
}

//追加元素
function insertAfter(newElement,targetElement){
	var parent = targetElement.parentNode;//获取目标元素的父节点
	if(parent.lastChild == targetElement){
	parent.appendChid(newElement);
	}else{
	parent.insertBefore(newElement,targetElement.nextSibling);
	//nextSibling是表示下一个兄弟元素节点
	}
}
//追加新的class
function addClass(element,value){
	if(!element.className){
		element.className = value;
	}else{
		newClassName = element.className;
		newClassName += " ";
		newClassName += value;
		element.className += newClassName;	
	}
}


index.css

*{margin: 0;padding: 0;list-style: none;}
.add{
	padding: 50px 40px 0 40px;
	background-color: #FAEBD7;
	width: 300px;
	height: 300px;
	position: absolute;
	left: 40%;
	top: 25%;
	
}
//清除父元素浮动
.add ul li:after{
	margin: 0 0 10px 0;
	content:"";
	display:block;
	clear:both;

}
.add ul li:nth-child(1) input,li:nth-child(2) input,li:nth-child(4) input,li:nth-child(5) input,li:nth-child(6) input{
	position: absolute;
	right: 10%;
}
.add ul li:nth-child(3) div{
	margin: 0;
	padding: 0;
	width: 160px;
	float: right;//使rdio和input对齐
}
.add ul li span{
	
}
.add ul:nth-child(2) li button{
	width: 100px;
	background-color: cornflowerblue;
	position: absolute;
	right: 10%;
}
.backIndex button{
	width: 100px;
	height: 50px;
	background-color: #eee;
	position: absolute;
	top: 25%;
	right: 25%;
}


add.css

*{margin: 0;padding: 0;}
/* 首页 */
.main{
	background-color: antiquewhite;
	position: absolute;
	left: 30%;
	top: 20%;


}
.table{
	width: 600px;
	
}
.tr td,th{
	text-align: center;
	width: 200px;
	height: 50px;
}
.goAdd button{
	width: 100px;
	height: 50px;
	background-color: #eee;
	position: absolute;
	top: 20%;
	right: 20%;
}


四、后端

1、搭建后台框架及构建配置文件

1)目录结构及介绍

image-20200806114635403

  • config:配置类,放置一些配置类,例如c3p0连接池配置,跨域请求配置等
  • constant:常量类,通常放置枚举类型常量,供其他类使用
  • controller:前端控制器,作用相当于xml,为前台提供接口
  • dto:将实体类entity包装,避免数据库的接口直接暴露出来
  • entity:实体类,相当于vo,存放数据库对应的实体对象
  • repository:数据访问层,相当于dao,sql语句一般在这里写
  • service:数据服务层:业务逻辑的实现层
  • util:工具类
  • BigproductApplication:启动类,springboot的启动器
  • pom.xml:依赖配置,在这里配置需要的依赖

2)构建配置文件——yml

image-20200806120112360

配置文件位于resources中,这里创建的了三个配置文件

  • application-yml:主配置类,主要配置类可以激活其他的一些配置
  • application-dev.yml:开发环境配置
  • application-pro.yml:生产环境(项目发布后)配置

源码及解析(以下有些配置可能前期开发阶段不需要)

application.yml

#配置spring
spring:
  profiles:
    active: dev #激活开发模式配置文件
#配置服务server
server:
  #配置tomcat服务
  tomcat:
    uri-encoding: utf-8  #使tomcat在解析参数的时候采用utf-8编码格式,如果未指定则采用ISO-8859-1编码解析
    max-connections: 3000 #最大连接数
    max-http-form-post-size: 1048576 #(1Mb)最大的post请求数,tomcat7之后,-1代表不限制请求,7之前0代表不限制请求
    max-http-header-size: 1048576 #请求头部最大值(1Mb)
c3p0:
  jdbcUrl: jdbc:mysql://127.0.0.1:3306/stumanger?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
  user: root
  password: 123456
  driverClass: com.mysql.jdbc.Driver #数据库连接驱动类
  minPoolSize: 2 #最小连接数
  maxPoolSize: 100 #最大的连接数
  maxIdleTime: 1800000 #创建过的链接并使用后闲置下来的闲置时间,如果超过这个时间就会自动断开这个连接
  acquireIncrement: 3 #当连接池中的连接耗尽的时候c3p0一次同时获取的连接数
  maxStatements: 1000 #JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭
  initialPoolSize: 3 #初始化时获取连接数
  idleConnectionTestPeriod: 60 #每60秒检查所有连接池中的空闲连接
  acquireRetryAttempts: 30 #定义在从数据库获取新连接失败后重复尝试的次数
  acquireRetryDelay: 1000 #两次连接中间隔时间,单位毫秒
  breakAfterAcquireFailure: false #获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。Default: false
  testConnectionOnCheckout: false #因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable等方法来提升连接测试的性能

application-dev.yml

server:
  port: 8081 #服务端口为8081
  servlet:
    session:
      timeout: -1 #设置session用不过期
spring:
  jpa:
    hibernate:
      ddl-auto: update #如果启动时表格式不一致则更新表,原有数据保留
      show-sql: true #是否打印生成的sql语句

application-pro.yml

server:
  port: 8081
  servlet:
    session:
      timeout: 2h #session保存两个小时
spring:
  jpa:
    hibernate:
      ddl-auto: none
      show-sql: false

3)使用jpa创建表

1、原理

​ 在写配置文件的时候,我们写过如下一段代码

spring:
  jpa:
    hibernate:
      ddl-auto: update #如果启动时表格式不一致则更新表,原有数据保留
      show-sql: true #是否打印生成的sql语句

​ 其中用springboot创建表的核心就是jpa,jpa中的ddl-auto:update就可以在程序运行启动的时候,将实体类映射到数据库中,将数据库中表跟新为当前实体类的格式类型,当然ddl-auto还有其他参数,如下:

  • create 启动时删数据库中的表,然后创建,退出时不删除数据表
  • create-drop 启动时删数据库中的表,然后创建,退出时删除数据表 如果表不存在报错
  • validate 项目启动表结构进行校验 如果不一致则报错
2、步骤

1)用Navicat创建一个数据库 stumanger

2)在entity中构建自己的实体类

image-20200806125659928

用其中学生表 Stu 举例:

package com.fjh.bigproduct.model.entity;

import javax.persistence.*;
import java.util.Date;

/**
 *@autho antg
 *@date 2020-08-05 20:48
*/
@Entity
@Table(name = "stu")
class Stu {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;
    //学号
    @Column(name="stu_no",columnDefinition = "varchar(255) comment'学号:2020+年级+班级 例如:20200101代表一年级一班,前4位表示入学年份'")
    private String stuNo;

    //学生姓名
    @Column(name="stu_name",columnDefinition="varchar(255) comment'学生姓名'")
    private String stuName;

    //性别
    @Column(name = "gender",columnDefinition = "int(11) comment'0:男,1:女'")
    private int gender;

    //班级
    @Column(name = "stu_class",columnDefinition = "varchar(255) comment'班级'")
    private String stuClass;

    //住址
    @Column(name = "stu_address",columnDefinition = "varchar(255) comment'住址'")
    private String stuAddress;

    //出生日期
    @Column(name = "stu_birthday",columnDefinition = "datetime comment'出生年月日'")
    private Date stuBirthday;
}

​ 指定表名

​ @Entity

​ @Table(name=“表名”)

​ 指定字段及属性

​ @Column(name=“字段名”,columnDefinition = “类型(长度) comment’注释’”)

3)启动springboot生成表

image-20200806130552357

2、后台代码编写

1)数据访问层(repository)

数据访问层相当于ssh项目中的dao,写操作数据库数据的方法

由于之前搭建的时候引入了jpa,所以在编写该层的时候可以继承数据访问的超级接口JpaRepository,然后就可以调用这个接口里面的方法就可以实现对数据库数据的crud。

先上代码,再逐个解释

package com.fjh.bigproduct.repository;


import com.fjh.bigproduct.model.entity.Stu;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import javax.transaction.Transactional;
import java.util.List;

/**
 *@autho antg
 *@Description 操作学生增删改查
 *@date 2020-08-17 17:16
*/

@Repository
public interface StuRepository extends JpaRepository<Stu,Integer> {
    //查询出所有未删除的学生
    @Query("from Stu where delState = 0")
    List<Stu> findAll();

    //根据id查询学生
    Stu findStuById(int id);

    //保存编辑一个学生信息
    //直接使用jpa封装好的save方法就行


}

1、注解:@Repository

这个注解用来标识这是一个数据访问层的类或者接口,并且在spring扫描的时候会将其加入到bean中

2、public interface StuRepository extends JpaRepository<Stu,Integer>

这个StuRepository接口继承了jpa提供的超级数据访问接口JpaRepository<T,ID>,(这里的接口用到了自定义泛型,可以理解为“参数”,不过这个参数有些特殊,这俩参数是用来限定JpaRepository中方法的泛型的,下面来一部分源码解释一下)

image-20200820225103476

那么StuRepository就可以使用jpa提供的所有数据访问方法。(这里的JpaRepository<T,ID>接口无法使用jpa的高级属性,如果要使用高级属性的话,需要继承JpaSpecificationExecutor,这个我也没用过(手动狗头))

3、查询出所有未删除的学生

这里使用了一个注解@Query,这个注解可以让我们使用自己定义的方法就例如下面这一段代码

@Query("from Stu where delState = 0")
    List<Stu> findAll();

我想要找到数据库中所有删除标志为0的数据,那么使用jpa自带的几个方法可能就不够用了,那就需要自己定义方法。

里面的语句可能写习惯sql语句的同学会看不懂,这里其实使用的叫HQL语句,是一种面向对象的查询语句,可以百度一下,语法比较简单,但是如果有同学就想写sql语句这么办呢?不慌,可以使用下面的写法

@Query("select * from stu where del_state = 0",nativeQuery = true)
    List<Stu> findAll();

nativeQuery属性默认是false的,若变为true就可以使用原生的sql语句

4、根据id查询学生

Stu findStuById(int id);

这里使用的是jpa提供的接口,么的说,直接写就行

5、保存编辑一个学生信息

一般像4中那些方法都不写的,能简单就简单,除非要自定义写sql语句,否则不在这一层写那么重复的代码

2)数据业务层(service)

目录结构:

image-20200821151422606

根据面向接口编程的原则,我们这里写了一个接口和一个实现类

这一层我们主要用来写主要的业务逻辑代码,相当于action

1、接口StuService

package com.fjh.bigproduct.service;

import com.fjh.bigproduct.model.dto.StuDto;
import com.fjh.bigproduct.model.entity.Stu;

import java.util.List;

/**
 *@autho antg
 *@Description 学生管理
 *@date 2020-08-17 17:30
*/

public interface StuService {
    //查找所有未删除学生
    List<Stu> findAllStu();
    //删除某一学生
    void delStu(int id);
    //保存或者编辑一个学生(id不为空则编辑,id为空则新增)
    void saveStu(StuDto stuDto);
    //根据学生id查找学生
    Stu findStu(int id);

}

规定了接口后,我们可以更加直观来展现实现类,也方便了编程

2、实现类StuServiceImpl

package com.fjh.bigproduct.service;

import com.fjh.bigproduct.model.dto.StuDto;
import com.fjh.bigproduct.model.entity.Stu;
import com.fjh.bigproduct.repository.StuRepository;
import com.fjh.bigproduct.util.DateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 *@autho antg
 *@Description 学生管理实现类
 *@date 2020-08-17 17:44
*/

@Service //标注这是一个服务层,并在spring扫描的时候加入到bean中
public class StuServiceImpl implements StuService{
	//引入数据访问层
    @Autowired
    private StuRepository stuRepository;


    //查询所有未删除的学生
    @Override
    public List<Stu> findAllStu(){
        try{
            return stuRepository.findAll();
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    //根据id查找学生
    @Override
    public Stu findStu(int id) {
        try {
            return stuRepository.findStuById(id);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    //根据id删除某一个学生
    @Override
    @Transactional //加上这个注解后不用保存就可以直接更新
    public void delStu(int id) {
        try {
                Stu stu = stuRepository.findStuById(id);
                stu.setDelState(1);
                stu.setDelTime(new Date());//这里没有保存,但是执行了方法后数据库就直接跟新了
        } catch (Exception e) {

            e.printStackTrace();
        }
    }

    //保存或者编辑一个学生(id不为空则编辑,id为空则新增)
    @Override
    public void saveStu(StuDto stuDto) {
        try {
            Stu stu = new Stu();
            //新增
            if(stuDto.getId() == 0){
                stu.setStuName(stuDto.getStuName());
                stu.setGender(stuDto.getGender());
                stu.setStuNo(stuDto.getStuNo());
                stu.setStuClass(stuDto.getStuClass());
                stu.setStuAddress(stuDto.getStuAddress());
                stu.setStuBirthday(DateUtil.parseString2Date(stuDto.getStuBirthday()));
                stu.setCreatTime(new Date());
                stu.setDelState(0);

                stuRepository.save(stu);
                //下面可以加操作日志
                //mycode
            //编辑
            }else {
                stu.setId(stuDto.getId());
                stu.setStuName(stuDto.getStuName());
                stu.setGender(stuDto.getGender());
                stu.setStuNo(stuDto.getStuNo());
                stu.setStuClass(stuDto.getStuClass());
                stu.setStuAddress(stuDto.getStuAddress());
                stu.setStuBirthday(DateUtil.parseString2Date(stuDto.getStuBirthday()));
                stu.setCreatTime(new Date());
                stu.setDelState(0);
                stuRepository.save(stu);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

总结一下服务层实现的步骤

1、引入注解@Service

2、引入数据访问层并加上注解@Autowired,

//引入数据访问层
    @Autowired
    private StuRepository stuRepository;//引入了之后就可以用stuRepository调用数据访问层的方法了

@Autowired注解可以对类成员变量、方法、构造函数进行标注,完成自动装配工作,通过@Autowried自动装配,可以实现从IoC容器中去查找bean中存储的对象,并返回。

3、实现接口的方法

里面使用了jpa提供的save方法,这个方法可以同时用在编辑和保存上,如果save的对象的id在数据库中存在,那么就更新,如果不存在就新增

这里的删除方法还使用了一个小技巧,@Transactional

这个注解可以实现不用save就可以自动更新

//根据id删除某一个学生
    @Override
    @Transactional //加上这个注解后不用保存九可以直接更新
    public void delStu(int id) {
        try {
                Stu stu = stuRepository.findStuById(id);
                stu.setDelState(1);
                stu.setDelTime(new Date());
            //这里只用了set方法就可以直接将数据库中的值更新
        } catch (Exception e) {

            e.printStackTrace();
        }
    }

3)前台控制器(controller)

package com.fjh.bigproduct.controller;

import com.fjh.bigproduct.model.dto.StuDto;
import com.fjh.bigproduct.model.entity.Stu;
import com.fjh.bigproduct.service.StuServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;

/**
 *@autho antg
 *@Description 前台控制器
 *@date 2020-08-19 10:16
*/
@RestController
@RequestMapping("/stu")
@ResponseBody
public class StuController {
    //这里加上final可以理解为单例模式,优化程序
    private final StuServiceImpl stuService;
    
	//为stuService赋初始值
    @Autowired
    public StuController(StuServiceImpl stuService) {
        this.stuService = stuService;
    }

    //显示学生列表
    @GetMapping("/findAllStu")
    public List<Stu> findAllStu(){
        try {
            List<Stu> list = stuService.findAllStu();
            return list;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    //根据id查询学生
    @GetMapping("/findStu")
    public Stu findStu(int id){
        try {
            return stuService.findStu(id);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    //添加学生;编辑学生
    @PostMapping("/saveStu")
    public void addStu(@RequestBody StuDto stuDto){
        stuService.saveStu(stuDto);
    }

    //删除学生
    @GetMapping("/delStu")
    public void delStu(@RequestParam int id){
        stuService.delStu(id);
    }
}

这个前台控制器相当于以前的xml,主要为页面提供访问接口

1、注解

@RestController

这个controller注解可以返回一些对象,为前台提供数据,这个注解还有一个兄弟,叫做@Controller,这个注解返回值是一个页面路径,表示要展示的页面或者跳转到另外一个请求

@RequestMapping("/stu")

RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径,这个注解可有可无,不过加在方法上的Mapping必须要有

地址/stu/方法Mapping

@ResponseBody

这个注解可以将后台返回的数据以json格式返回,否则返回的是一个Object对象,加在类上,该类的所有方法都会将数据以json格式返回

2、调用数据服务层StuServiceImpl

    //这里加上final可以理解为单例模式,优化程序
    private final StuServiceImpl stuService;
    
	//为stuService赋初始值
    @Autowired
    public StuController(StuServiceImpl stuService) {
        this.stuService = stuService;
    }

3、向前台传值

//显示学生列表
    @GetMapping("/findAllStu")
    public List<Stu> findAllStu(){
        try {
            List<Stu> list = stuService.findAllStu();
            return list;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

这是一个显示学生列表的方法,前台使用get方法调接口/stu/findAllStu就可以获取rturn的值,这个值将以json的数据格式发送到前台(因为在使用了注解@@ResponseBody)

4、获取参数

(1)获取get请求中的参数

//删除学生
@GetMapping("/delStu")
public void delStu(@RequestParam int id){
    stuService.delStu(id);
}

这里使用了@RequestParam注解, 后面的参数类型名称要和前台传的要一致

(2)获取json对象

//添加学生;编辑学生
    @PostMapping("/saveStu")
    public void addStu(@RequestBody StuDto stuDto){
        stuService.saveStu(stuDto);
    }

这里使用了@RequestBody来获取参数 后面跟上一个dto对象用来封装前台的json对象,一般前台提交json对象都用POST方法来响应

image-20200821171815535

这里的dto一般就是用来封装前台传来的json对象

dto源码:

package com.fjh.bigproduct.model.dto;

import java.util.Date;

/**
 *@autho antg
 *@Description 封装stu对象
 *@date 2020-08-20 08:44
*/


public class StuDto {

    private int id;

    private String stuNo;

    private String stuBirthday;

    private String stuAddress;

    private String stuClass;

    private int gender;

    private String stuName;

    public int getId() {
        return id;
    }

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

    public String getStuNo() {
        return stuNo;
    }

    public void setStuNo(String stuNo) {
        this.stuNo = stuNo;
    }

    public String getStuBirthday() {
        return stuBirthday;
    }

    public void setStuBirthday(String stuBirthday) {
        this.stuBirthday = stuBirthday;
    }

    public String getStuAddress() {
        return stuAddress;
    }

    public void setStuAddress(String stuAddress) {
        this.stuAddress = stuAddress;
    }

    public String getStuClass() {
        return stuClass;
    }

    public void setStuClass(String stuClass) {
        this.stuClass = stuClass;
    }

    public int getGender() {
        return gender;
    }

    public void setGender(int gender) {
        this.gender = gender;
    }

    public String getStuName() {
        return stuName;
    }

    public void setStuName(String stuName) {
        this.stuName = stuName;
    }
}

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Antgeek

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值