Servlet基础
定义
Servlet是一种服务器端的Java应用程序,具有独立于平台和协议的特性,可以生成动态的Web页面。 它担当客户请求(Web浏览器或其他HTTP客户程序)与服务器响应(HTTP服务器上的数据库或应用程序)的中间层。 Servlet是位于Web 服务器内部的服务器端的Java应用程序,与传统的从命令行启动的Java应用程序不同,Servlet由Web服务器进行加载,该Web服务器必须包含支持Servlet的Java虚拟机。
WEB
WEB服務器:用于接收请求,产生响应,但是响应信息只能产生静态HTML
WEB容器:将服务器请求,进行一大堆业务处理,然后以数据库作为信息储存介质,动态产生响应信息,再不改变页面的情况下,做到数据的及时更新
http协议
HTTP协议称为超文本传输协议,是TCP协议的应用层协议,是客户端与服务器通信的一种标准。客户端和服务器都遵循HTTP协议,就能从彼此发送的信息中提取自己想要的数据。
http协议的特点
1、http遵循请求/响应模型
2、http协议是一种无状态的协议。当客户端和服务器之间,请求/响应流程结束后,连接会断开。客户端每次请求都需要重新建立连接。所以,服务器会认为每次请求的都是新用户,无法知道两次请求的用户是否为同一个用户。
3、http协议占用80端口。短连接。
http协议的长连接
在网页中,除了有文本数据以外,还有各式各样的连接资源。在网页显示时,不仅仅有文本数据,还需要将链接资源一一下载并显示。这时,如果每次请求都建立连接,效率会比较低。所以,在HTTP/1.1标准中,用长连接来解决。在访问网页时,建立连接,在下载连接资源时,就不用重新建立连接了。
http协议的处理流程
1、客户端和服务器建立连接
2、客户端发出http请求
3、服务器产生http响应
4、关闭连接
http协议请求信息的格式
分为四部分:请求行、请求头、空行、消息体。
请求行:描述请求方式、请求的URL路径、HTTP协议的版本
请求头:以键值对方式描述客户端相关的信息
空行:标识请求头的结束
消息体(POST):描述客户端请求服务器的表单数据
http协议的请求方式
GET,POST,HEAD,OPTIONS,PUT,DELETE,TRACE,CONNECT
其中最常用的是GET、POST两种
现在有一种风格叫rest风格,该风格认为GET请求用于查询操作,POST请求用于添加操作,DELETE请求用于删除操作,PUT请求用于修改操作。
GET请求:1、在浏览器中直接输入URL路径,访问服务器。
2、点击超链接
3、提交表单时。method属性缺省,或为GET
POST请求:提交表单时,method属性为POST
GET请求和POST请求的区别
1、流格式的区别。
GET请求的表单数据附加在URL路径后面,没有消息体。所以,在GET请求时,浏览器地址会显示表单数据。POST请求的表单数据放在消息体中,在POST请求时,浏览器地址栏不会显示表单数据,相对安全。
2、传属性能的区别。
- GET请求只能传输文本数据,POST请求可以传输文本数据和二进制数据
- GET请求只能传输小文本数据,POST请求数据传输没有大小限制
3、用途的区别
GET请求用于服务器资源的查找。而POST用于数据的传输,也就是将客户的数据传输给服务器。
http协议的响应信息
状态行、响应头、空行、消息体
状态行:描述HTTP协议的版本、状态码、状态描述
响应头:以键值对方式描述服务器相关信息
空行:标识响应头的结束
消息体:服务器发送给客户端的具体数据。
状态码
100-199:标识信息性代码,请求在进行中
200-299:标识客户端请求成功,服务器数据正确到达客户端
300-399:表示服务器资源已经移走,只是客户端请求新的地址
400-499:表示由客户端引发的错误
500-599:表示由服务器引发的错误
MIME类型
用于指定服务器发送给客户端的数据格式。客户端接收到响应信息后,会根据服务器指定的MIME类型,来决定如何解析响应信息的消息体内容
常见的MIME类型:
text/html:网页格式数据
image/jpeg:jpg图片格式
text/xml:xml格式数据
application/json:json格式数据
辅助应用
传统的web服务器在产生响应信息时,只能产生静态的html页面。极大的影响响应信息的灵活性。
解决方案是在传统的web服务器基础上,增加辅助应用。辅助应用可以在web服务器接收到客户端请求之后,进行一大堆业务处理。并以数据库作为数据存储界质,从而动态显示处理的响应信息。
java采用WEB容器+Servlet作为辅助应用解决方案的
web容器
在java中,web容器完成底层操作。预留Servlet接口,交给开发者书写业务操作。web容器调用servlet业务方法,动态产生相应信息。
web容器的作用
1、通讯支持
由于请求/响应信息比较庞大。容器需要将请求/响应信息,封装为请求对象和响应对象。以便更好的接收和发送数据。
2、Servlet组件生命周期管理
Servlet是WEB容器预留给开发者书写业务操作的接口。开发者实现了Servlet接口后,Servlet组件对象的产生、方法调用、销毁全部由WEB容器进行。
3、线程支持
WEB容器采用多线程作为多任务处理解决方案。线程的创建、启动、同步、销毁全部由WEB容器管理。
4、JSP支持
由WEB容器完成对JSP引擎的编写,完成JSP页面的翻译
5、处理安全性
tomcat
tomcat源自于apache软件基金会jakata项目。tomcat是一款免费的、开源的、性能稳定、技术成熟的WEB容器产品。
导入tomcat依赖
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>9.0.36</version>
</dependency>
Servlet是运行在Web服务器或应用服务器上的java程序,是WEB容器和开发者业务组件通信的标准。由Sun规范了其功能。
Servlet的API结构
按照Servlet规范,Servlet为业务接口,提供service()交给开发者书写业务操作,ServletConfig为配置接口。由于两个接口中的方法较多,如果都实现会很繁琐,servlet规范中提供了一个GeneriServlet类,该类同时实现了Servlet和ServletConfig两个接口,并实现了大部分方法。但是没有实现service方法,该方法应该由子类,根据协议的特点进行重写。
HttpServlet继承了GenericServlet,根据http协议的特点,重写doGet和doPost方法就可以了。
步骤
1、书写Servlet类并继承HttpServlet,重写doGet和doPost方法
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置响应信息的MIME类型和编码集
resp.setContentType("text/html;charset=utf-8");
//向客户端输出信息
resp.getWriter().print("hello,中国");
}
}
2、创建并启动Tomcat,同时注册servlet
public class MainTomCat {
public MainTomCat() {
Tomcat tomcat = new Tomcat();
//设置启动端口
tomcat.setPort(8088);
//设置http引擎
tomcat.getConnector();
//定义上下文
Context context = tomcat.addContext("", null);
//注册servlet。第一个参数为上下文对象,第二个参数为servlet名称,第三个参数为servlet对象
Wrapper w = Tomcat.addServlet(context, "test", new TestServlet());
//注册servlet访问路径
w.addMapping("/tt");
try {
//启动tomcat
tomcat.start();
} catch (LifecycleException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new MainTomCat();
}
}
servlet访问路径
1、精确匹配:/test 表示客户端以/test请求服务器,由该servlet处理。
2、扩展匹配:*.do 表示凡是以do结尾的请求,都该由servlet处理。
3、路径匹配:/abc/* 表示凡是在/abc/目录下的请求,都该由servlet处理。
常用API
//设置请求信息编码集,只对POST有效
req.setCharacterEncoding("utf-8");
//设置响应信息的MIME类型的编码集
resp.setContentType("text/html;charset=utf-8");
//根据表单名得到表单值
String userName = req.getParameter("userName");
//客户端提交多个同名的键值对,由getParameterValues接收,返回数组
String[] likeArray = req.getParameterValues("like");
resp.getWriter().print("姓名:" + userName + "<br>");
resp.getWriter().print("爱好:" + Arrays.toString(likeArray) + "");
服务器产生响应信息有两种格式
1、向客户端发送文本数据
resp.getWriter().printLn("信息")
2、向客户端发送二进制数据
OutputStream out = resp.getOutputStream()
将对象转化为json格式字符串
1、导入依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-parameter-names</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jdk8</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.11.0</version>
</dependency>
2、对于实体类的日期类型,需要加上输入格式
public class ClassBean {
private Integer id;
private String name;
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate createDate;
}
3、利用ObjectMapper将对象,转化为json字符串
ObjectMapper om = new ObjectMapper();
//添加日期格式的支持
om.registerModule(new JavaTimeModule());
//将对象转化为json格式字符串
String str = om.writeValueAsString(list);
Servlet生命周期
1、容器加载并实例化Servlet
2、调用init()完成初始化
3、当请求达到,调用service(),接收请求,产生响应。
4、销毁阶段,调用destory(),完成资源清理。
在整个生命周期中,1、2、4只做一次。只有3,每次请求都会执行。而Servlet组件是单实例,多线程的类。
Servlet接口中定义的init()方法,用于servlet组件类的初始化。初始化的时机是可以配置的。如果配置了LoadOnStartup,并设置为0或正数。表示容器启动就完成该servlet初始化。如果没有配置LoadOnStartup,或设置为负数。表示第一次访问servlet时,完成初始化。
SpringMVC
是一个基于MVC模式的表现层框架,在spring2.5以后新增了注解功能。
特点
1、基于的是servlet模式
2、控制器不再需要继承其它类,只需要用@Controller注解
3、应用控制器方法参数,由前端控制器负责封装,方法签名定义灵活。
4、返回页面直接在方法中指定,可以是String,也可以是其它的,比如:ModelAndView或void等
5、性能很优秀
控制器
在springMVC中存在两种控制器:前端控制器和应用控制器。
前端控制器(DispatcherServlet),负责接收客户端请求,根据请求路径访问应用控制器,负责将页面参数填充JavaBean,负责转发页面,对标签类进行调用。
应用控制器(用户书写的Controller),负责产生业务组件,调用业务组件的方法完成业务,根据结果返回转发的页面对象。
工作流程
1、当客户端请求服务器,服务器使用前端控制器DispatcherServlet接收请求。
2、DispatcherServlet借助HandlerMapping,根据请求的URL路径,定位到具体的Controller,和应用控制器的具体方法。并将封装好数据的实体对象传入应用控制器。
3、由应用控制器方法,完成业务组件的业务方法的调用,然后根据业务方法处理的结果,返回需要转发的页面路径。DispatcherServlet根据路径,完成页面转发。
Spring Boot
SpringBoot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程中。
特点
1、创建独立的Spring应用程序
2、嵌入的Tomcat,无需部署WAR文件
3、简化Maven配置
4、自动配置Spring
5、对XML没有要求配置
环境搭建
1、导入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.7</version>
<relativePath/>
</parent>
SpringBoot 是由一系列启动器组成的,这些启动器构成一个强大的灵活的开发助手。开发人员根据项目需求,选择并组合相应的启动器,就可以快速搭建一个适合项目需要的基础运行框架。
2、添加web启动器的坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
3、添加启动类
/**
* 扫描该类所在的包,及子包中的spring组件类
*/
@SpringBootApplication
public class BootMain {
public static void main(String[] args) {
SpringApplication.run(BootMain.class);
}
}
4、书写应用控制器
@RestController
public class TestController {
@RequestMapping("info")
public String getInfo() {
return "hello,典韦";
}
@RequestMapping("sp")
public String speak() {
return "说话";
}
}
springboot的配置文件
SpringBoot有很多的自动配置,在开发中,我们可能需要修改SpringBoot自动配置的默认值。比如,服务器启动端口,数据源等。
springBoot的配置文件必须放在类路径下,名称是固定。application.yml和application.properties
applicationContext.properties 内容:
server.port=8088
server.context=/boot
applicationContext.yml 内容:
server:
port:8088
context:/boot
SpringBoot静态资源存放目录,需要在classPath类路径下。如果是maven项目,则在resource,目录下。
classPath:
META-INF/resources>resources>static>public
springBoot得到表单数据
@RequestMapping("add")
public String add(EmployeeBean em) {
return "添加成功" + em ;
}
springBoot会按表单名和属性名相同的原则,进行实体对象属性的封装。简单类型形参,按照表单名和形参名相同的原则进行封装。
当形参名和表单名不一致时,可以用@RequestParam指定什么表单值填充该形参。
@RequestMapping("add")
public String add(EmployeeBean em, @RequestParam("money") Integer mone) {
return "添加成功" + em + mone;
}
SpringBoot类型转换
在springBoot中内置大量的类型转换器。可以完成大部分类型的转化。不过,如果是一些特殊类型(LocalDate),或需要自定义转换规则时,就要自定义类型转换器。
@Component
public class DateChange implements Converter<String, LocalDate> {
@Override
public LocalDate convert(String source) {
if (source.matches("\\d{4}-\\d{2}-\\d{2}")) {
return LocalDate.parse(source);
}
return null;
}
}
springBoot命名空间
在开发中,为了防止URL同名而导致的异常。可以在方法申明URL路径时,加上命名空间
@RestController
@RequestMapping("room")
public class RoomController {
@RequestMapping("add")
public String add() {
return "添加房间";
}
}
这时,add方法的访问路径,就应该是“/room/add”
有时候,在应用控制器方法中,也需要使用servlet容器中对象,这时,可以直接在应用控制器方法中,添加形参。
public class RoomController {
@RequestMapping("add")
public String add(HttpServletRequest req, HttpServletResponse resp) {
return "添加房间";
}
在springMVC中,应用控制器方法可以返回字符串,这时客户会原样输出该字符串(@RestController)。如果应用控制器方法返回实体对象,或集合,那么会将实体对象或集合转化为json字符串,输出到客户端。
@RequestMapping("findAll")
public List<EmployeeBean> findAll() {
List<EmployeeBean> list = new ArrayList<>();
list.add(new EmployeeBean(2, "佳伟", "19273919211", 2830, LocalDate.parse("1998-09-01")));
list.add(new EmployeeBean(4, "大卫", "19323919211", 8818, LocalDate.parse("1998-09-01")));
return list;
}
关于表单、超链接访问路径的问题
表单的action属性和超链接的href属性,表示该表单或超链接的访问服务URL路径。有两种写法:
<form action="user/reg">
<input type="submit" value="提交">
</form>
如果URL路径以/开始,表示在根目录下查找指定资源
<form action="/user/reg">
<input type="submit" value="提交">
</form>
在应用控制器方法中,可以指定该方法必须以什么方式来请求
14:27@RequestMapping(value = "reg",method = RequestMethod.GET)
public String add(){
return "注册";
}
表示该方法只能以GET方式来访问,如果以别的方式访问,会抛出405状态码。
也可以直接使用@PostMapping、@GetMapping代替@RequestMapping。指定请求方式
从请求URL路径中,得到客户端提交的数据
在客户端提交URL路径时,通过/附加数据
<a href="/user/del/1/tom/123">删除</a>
服务端,接收URL路径中的数据
@RequestMapping("del/{id}/{name}/{grade}")
public String del(@PathVariable("id") Integer id,
@PathVariable("name") String userName,
@PathVariable("grade") Integer grade) {
return "删除成功" + id + userName + grade;
}
请求参数的默认值
@RequestMapping("find")
public String find(@RequestParam(value = "id", defaultValue = "2") Integer id) {
return "id=" + id;
}
表示,如果客户端提交了id表单数据,就以客户端提交的id值填充形参,如果客户端没有提交id表单数据,这时,以默认值1填充形参。
MyBatis-Plus
是一个MyBatis的增强工具,在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生。
官网:https://mp.baomidou.com/
环境搭建
1、导入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.7</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.9</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
</dependencies>
2、创建实体类,同时映射表名和列名,将属性名映射列名
@TableName("t_student")//表示该类映射的表名
public class StudentBean {
//表示该属性映射主键列,同时指定主键生成策略。IdType.AUTO表示使用数据库的自动增长列填充该属性。Value表示该属性映射的主键列名
@TableId(value = "pk_studentId", type = IdType.AUTO)
private Integer id;
//映射普通列
@TableField("s_name")
private String name;
@TableField("s_birthday")
private LocalDate birthday;
@TableField("s_phone")
private String phone;
3、创建配置文件application.yml
server:
port: 8088
spring:
datasource: #定义数据源
driver-class-name: com.mysql.cj.jdbc.Driver #驱动类
url: jdbc:mysql://localhost:3306/db?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useUnicode=true&useSSL=false&allowMultiQueries=true #URL
username: root #mysql登录用户名
password: yks957 #mysql登录密码
#指定连接池产品
type: com.alibaba.druid.pool.DruidDataSource
druid:
one:
max-active: 100 #最大连接
min_idle: 20 #最小连接
max-wait: 2000 #超时时间
mybatis-plus:
configuration:
#定义日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#允许指定包中的实体类,用类名做为别名
type-aliases-package: com.project.bean
#扫描mapper文件
mapper-locations: classpath:*/*Mapper.xml
4、创建springBoot启动类,启动类必须放在父包中
@SpringBootApplication
public class MainBoot3 {
public static void main(String[] args) {
SpringApplication.run(MainBoot3.class);
}
}
5、定义业务接口
public interface IStudentService {
public void add(StudentBean studentBean);
public void del(Integer id);
public void update(Integer id, String phone);
public List<StudentBean> findAll();
public StudentBean findById(Integer id);
}
6、定义mapper接口
@Mapper
public interface IStudentMapper extends BaseMapper<StudentBean> {
}
7、书写业务接口实现类
@Service
@Transactional
public class StudentServiceImpl implements IStudentService {
@Autowired
private IStudentMapper mapper;
@Override
public void add(StudentBean studentBean) {
mapper.insert(studentBean);//添加,同时将自动增长列的值填充主键属性
}
@Override
public void del(Integer id) {
mapper.deleteById(id); //按Id删除
}
@Override
public void update(Integer id, String phone) {
StudentBean studentBean = mapper.selectById(id);
studentBean.setPhone(phone);
mapper.updateById(studentBean);//按id修改
}
@Override
public List<StudentBean> findAll() {
return mapper.selectList(null);//查询所有
}
@Override
public StudentBean findById(Integer id) {
return mapper.selectById(id);//按Id查询
}
8、测试
@SpringBootTest(classes = MainBoot3.class)
public class StudentTest {
@Autowired
private IStudentService service;
@Test
public void test() {
System.out.println(service.findAll());
service.add(new StudentBean("猪猪", LocalDate.parse("2020-01-01"),"18726362718"));
System.out.println(service.findByName("张")); System.out.println(service.findByBirthday(LocalDate.parse("2000-01-01"),LocalDate.parse("2020-01-01")));
IPage<StudentBean> ip = service.cutAll(1);
System.out.println(ip.getRecords() + " " + ip.getTotal() + " " + ip.getPages());
}
}
条件查询
使用QueryWrappe绑定条件
@Override
public List<StudentBean> findByName(String name) {
QueryWrapper<StudentBean> qw = new QueryWrapper<>();
//精确查询,相当于= 判断是否相等
// qw.eq("s_name", name);
//模糊查询,相当于%aaa%
qw.like("s_name", name);
return mapper.selectList(qw);
}
public List<StudentBean> findByBirthday(LocalDate startDate, LocalDate endDate) {
QueryWrapper<StudentBean> qw = new QueryWrapper<>();
//大于等于
qw.ge("s_birthday", startDate);
//小于等于
qw.le("s_birthday", endDate);
return mapper.selectList(qw);
}
分页查询
1、注册分页插件
@Configuration
public class MyBatisConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(
new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
2、动态条件分页查询
@Override
public IPage<StudentBean> cutByItem(Integer pageNO, String name, LocalDate startDate, LocalDate endDate) {
QueryWrapper<StudentBean> qw = new QueryWrapper<>();
if (name != null && name.length() != 0) {
qw.like("s_name", name);
}
if (startDate != null) {
qw.ge("s_birthday", startDate);
}
if (endDate != null) {
qw.le("s_birthday", endDate);
}
return mapper.selectPage(new Page<>(pageNO, 3), qw);
}
关联查询
Mybatis-plus设计的初衷,是为了简化单表查询。如果需要进行联表操作,这时之前在实体类中定义的映射全部失效。需要重新定义resultMap映射。
一对多
1、定义实体类
@TableName("t_dept")
public class DeptBean {
@TableId(value = "pk_deptId", type = IdType.AUTO)
private Integer id;
@TableField("d_name")
private String name;
@TableField("d_master")
private String master;
@TableField(exist = false)
private List<EmployeeBean> emList;
}
在实体类中,如果属性没有映射数据表的列时,需要加@TableField(exist = false)标识该属性没有对应的数据库列。否则,mybatis-puls查询该属性同名的列。
@TableName("t_employee")
public class EmployeeBean {
@TableId(value = "pk_emId",type = IdType.AUTO)
private Integer id;
@TableField("e_name")
private String name;
@TableField("e_birthday")
private LocalDate birthday;
@TableField(exist = false)
private DeptBean dept;
@TableField("fk_deptId")
private Integer deptId;
}
多方操作
添加操作
1、定义业务接口方法
public void add(EmployeeBean em);
2、业务接口实现类
emMapper.insert(em);
查询员工,同时查询员工所在的部门名称
导入分页插件
@Configuration
public class MyBatisConfig {
@Bean
public MybatisPlusInterceptor getInterceptor() {
MybatisPlusInterceptor plus = new MybatisPlusInterceptor();
plus.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return plus;
}
}
1、定义业务接口方法
/**
* 按编号查询员工,同时查询员工所在部门信息
*
* @param id 员工编号
* @return 员工对象
*/
public EmployeeBean findById(Integer id);
2、业务接口实现类
@Service
@Transactional
public class EmployeeServiceImpl implements IEmployeeService {
@Autowired
private IEmployeeMapper emMapper;
@Autowired
private IDeptMapper deptMapper;
@Override
public EmployeeBean findById(Integer id) {
EmployeeBean employeeBean = emMapper.selectById(id);
employeeBean.setDept(deptMapper.selectById(employeeBean.getDeptId()));
return employeeBean;
}
}
联表动态条件分页查询
1、定义业务接口
public IPage<EmployeeBean> cutByItem(Integer pageNO, String emName, String deptName);
2、定义mapper接口
public IPage<EmployeeBean> cutByItem(Page pg, @Param("emName") String emName,@Param("deptName") String deptName);
3、书写mapper文件
<resultMap id="emMap" type="EmployeeBean">
<id property="id" column="pk_emId"></id>
<result property="name" column="e_name"></result>
<result property="birthday" column="e_birthday"></result>
<result property="dept.name" column="d_name"></result>
</resultMap>
<select id="cutByItem" resultMap="emMap">
select e.*,d.d_name from t_employee e,t_dept d where e.fk_deptId=d.pk_deptId
<if test="emName !=null and emName!=''">
and e_name like "%"#{emName}"%"
</if>
<if test="deptName!=null and deptName!=''">
and d_name like "%"#{deptName}"%"
</if>
</select>
4、书写业务方法
public IPage<EmployeeBean> cutByItem(Integer pageNO, String emName, String deptName);
一方操作
批量添加。添加部门同时添加部门员工
1、定义业务接口
/**
* 添加部门,同时添加该部门的员工
*
* @param deptBean 部门对象
* @param emList 员工集合
*/
public void add(DeptBean deptBean, List<EmployeeBean> emList);
2、定义mapper接口
public void addEmployeeList(@Param("deptId") Integer deptId, @Param("emList") List<EmployeeBean> emList);
3、书写mapper文件
<insert id="addEmployeeList">
insert into t_employee(e_name,e_birthday,fk_deptId) values
<foreach collection="emList" separator="," item="em">
(#{em.name},#{em.birthday},#{deptId})
</foreach>
</insert>
4、书写业务方法
public void add(DeptBean deptBean, List<EmployeeBean> emList) {
deptMapper.insert(deptBean);
deptMapper.addEmployeeList(deptBean.getId(), emList);
}
批量删除,删除部门同时删除部门员工
1、定义业务接口
/**
* 删除部门,同时删除该部门的员工
*
* @param id 部门id
*/
public void del(Integer id);
2、业务接口实现类
public void del(Integer id) {
QueryWrapper<EmployeeBean> qw = new QueryWrapper<>();
qw.eq("fk_deptId", id);
emMapper.delete(qw);
deptMapper.deleteById(id);
}
也可以在mapper接口中定义方法,书写SQL语句完成。
@Delete("delete from t_employee where fk_deptId=#{id};" + "delete from t_dept where pk_deptId=#{id}")
public void del(Integer id);
关联查询,查询部门。同时查询部门的员工信息
1、定义业务接口
/**
* 按id查询部门,同时查询该部门的员工信息
* @param id 部门id
* @return 部门对象
*/
public DeptBean findById(Integer id);
2、书写业务接口实现类
@Override
public DeptBean findById(Integer id) {
DeptBean deptBean = deptMapper.selectById(id);
QueryWrapper<EmployeeBean> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("fk_deptId", id);
deptBean.setEmList(emMapper.selectList(queryWrapper));
return deptBean;
}
多对多
多对多操作。大部分时候都是对中间表进行操作。一般情况,设置为单向的多对多。
用户实体类
@TableName("t_user")
public class UserBean {
@TableId(value = "pk_userId", type = IdType.AUTO)
private Integer id;
@TableField("u_name")
private String name;
@TableField(exist = false)
private List<GradeBean> gradeList;
}
权限实体类
@TableName("t_grade")
public class GradeBean {
@TableId(value = "pk_gradeId", type = IdType.AUTO)
private Integer id;
@TableField("g_name")
private String name;
}
添加用户,同时添加用户的权限
1、定义业务接口方法
/**
* 添加用户同时添加用户的权限
*
* @param userBean 用户对象
* @param gradeIdArray 权限id数组
*/
public void add(UserBean userBean, Integer[] gradeIdArray);
2、定义mapper方法
public void addGradeList(@Param("userId") Integer userId,
@Param("gradeArray") Integer[] gradeArray);
3、书写mapper文件
<insert id="addGradeList">
insert into t_user_grade(fk_userId,fk_gradeId) values
<foreach collection="gradeArray" item="gradeId" separator=",">
(#{userId},#{gradeId})
</foreach>
</insert>
4、书写业务方法
public void add(UserBean userBean, Integer[] gradeIdArray) {
userMapper.insert(userBean);
userMapper.addGradeList(userBean.getId(), gradeIdArray);
}
删除用户,同时删除用户权限
1、定义业务方法
/**
* 删除用户,同时删除用户权限
*
* @param id 用户id
*/
public void del(Integer id);
2、定义mapper方法
@Delete("delete from t_user_grade where fk_userId=#{userId}")
public void delUserGrade(Integer userId);
3、书写业务方法
public void del(Integer id) {
userMapper.deleteById(id);
userMapper.delUserGrade(id);
}
修改用户权限
1、定义业务方法
/**
* 修改用户权限
*
* @param id 用户id
* @param newGradeArray 新的权限id数组
*/
public void update(Integer id, Integer[] newGradeArray);
2、书写业务方法
public void update(Integer id, Integer[] newGradeArray) {
userMapper.delUserGrade(id);
userMapper.addGradeList(id, newGradeArray);
}
按id查询用户,同时查询用户的权限
1、定义业务方法
/**
* 按ID查询用户,同时查询用户权限
* @param id 用户id
* @return 用户对象
*/
public UserBean findById(Integer id);
2、定义mapper方法
public List<GradeBean> findByUser(Integer userId);
3、书写mapper文件
<mapper namespace="com.project.mapper.IGradeMapper">
<resultMap id="gradeMap" type="GradeBean">
<id property="pk_gradeId" column="id"></id>
<result property="name" column="g_name"></result>
</resultMap>
<select id="findByUser" resultMap="gradeMap">
SELECT g.*
FROM t_grade g,
t_user_grade ug
WHERE g.pk_gradeId = ug.fk_gradeId
AND ug.fk_userId = #{id}
</select>
4、书写业务方法
public UserBean findById(Integer id) {
UserBean userBean = userMapper.selectById(id);
userBean.setGradeList(gradeMapper.findByUser(id));
return userBean;
}