华清远见-重庆中心-框架阶段技术总结
框架
一套规范。
实际是他人实现的一系列接口和类的集合。通入导入对应框架的jar文件(maven项目导入对应的依赖),进行适当的配置,就能使用其中的所有内容。
开发者可以省去很多模板代码,如dao中的CRUD,MVC模式下层与层之间的关联。只需要集中精力实现项目中的业务逻辑部分。
Java主流框架
Spring、SpringMVC、MyBatis、MyBatisPlus、Hibernate、JPA等。
SSH:最初是Spring+Stucts2+Hibernate组成,之后Stucts2被SpringMVC取代。
SSM:Spring+SpringMVC+MyBatis
新项目使用SpringBoot,早起的SSH项目由于维护成本高,基本不会推翻重做,但会维护一些SSM项目。
无论是SSH还是SSM,Spring、SpringMVC必不可少。从2004年推出至今,依旧是主流框架中不可获取的一部分。
Spring
概念
一个轻量级开源的Java框架。是一个管理项目中对象的容器,同时也是其他框架的粘合器,目的就是对项目进行解耦。
轻量级:对原有代码的侵入很小。
Spring的核心是IOC控制反转和AOP面向切面编程
Spring控制台应用
1.创建一个普通的Maven项目,不选择模板
2.添加Spring核心依赖
jdk8用5.x版本
<!-- spring-context表示spring核心容器 -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.23</version>
</dependency>
3.创建一个Java类
package com.hqyj.spring01;
/*
* 定义一个普通的Java类
* PlainOrdinaryJavaObject pojo 相当于简化的javabean
* entity vo dto pojo 都是在描述实体类
* */
public class PlainOrdinaryJavaObject {public void fun(){System.out.println("一个PlainOrdinaryJavaObject(普通的Java类)对象");}
}
4.创建Spring配置文件
创建一个Spring的配置文件,在其中注入上一步创建的类的对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gnok4nsK-1676798005638)(D:\框架\Spring01.assets\image-20230112110130552.png)]
在resources目录下,创建一个xml文件,选择spring config,通常命名为application
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--bean标签表示,在Spring容器中,注入某个类的对象--><!--class属性表示要注入哪个类,写类的全限定名(包名+类名)--><!--id表示给类的对象的名称--><bean class="com.hqyj.spring01.PlainOrdinaryJavaObject" id="pojo"></bean></beans>
5.创建main方法所在类
解析Spring配置文件,获取注入的对象。
package com.hqyj.spring01;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Main {public static void main(String[] args) {//创建一个自定义类的对象//传统方式创建对象//PlainOrdinaryJavaObject pojo = new PlainOrdinaryJavaObject();//使用spring容器获取对象//创建一个用于解析Spring配置文件的对象,参数为配置文件的名称。实际就是获取Spring容器ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");//获取容器中的对象/*只通过名称获取,返回值为Object类型,需要转换Object obj = context.getBean("pojo");PlainOrdinaryJavaObject pojo=(PlainOrdinaryJavaObject) obj;*///使用这种方式,直接用指定类型接收PlainOrdinaryJavaObject pojo = context.getBean("pojo", PlainOrdinaryJavaObject.class);//能成功调用方法,说明Spring管理了该类的对象pojo.fun();//关闭Spring容器context.close();}
}
bean标签常用属性
属性 | 作用 |
---|---|
class | 定义类的全限定名 |
id | 定义对象的名称 |
lazy-init | 是否为懒加载。默认值为false,在解析配置文件时就会创建对象。设置为true表示懒加载,只有在getBean()时才会创建对象。 |
scope | 单例/原型模式。默认值为singleton,表示单例模式,只会创建一个对象。设置为prototype,表示原型模式,每调getBean()就创建一个对象。 |
init-method | 初始化时触发的方法。在创建完该对象时自动调用的方法。该方法只能是无参方法,该属性的值只需要写方法名即可 |
destory-method | 销毁时触发的方法。Spring容器关闭时自动调用的方法,该方法只能是无参方法。只有在单例模式下有效。 |
属性注入
给某个bean添加属性的方式有两种:构造器注入和setter注入
setter注入
这种方式注入属性时,类中必须要有set方法
在bean标签中,加入<property></property>
标签,
该标签的name属性通常表示该对象的某个属性名,但实际是setXXX()方法中的XXX单词。
如有age属性,但get方法为getNianLing(),name属性就需要写成nianLing。
该标签的value属性表示给该类中的某个属性赋值,该属性的类型为原始类型或String。
该标签的ref属性表示给该类中除String以外的引用类型属性赋值,值为Spring容器中另一个bean的id。
<!--注入Car类对象并用set方式注入其属性-->
<bean class="com.hqyj.spring01.Car" id="c"><!--该属性是字符串或原始类型,使用value赋值--><property name="brand" value="宝马"></property><!--name并不是类中是属性名,而是该属性对应的getXXX()方法中XXX的名称--><!--如Car类中有color属性,但get方法名为getColo(),这里就要写为colo--><property name="colo" value="白色"></property>
</bean><!--注入Person类对象并用set方式注入其属性-->
<bean class="com.hqyj.spring01.Person" id="p1"><property name="name" value="王海"></property><property name="age" value="22"></property><!--属性是引用类型,需要通过ref赋值,值为另外的bean的id ref即references--><property name="car" ref="c"></property>
</bean>
构造方法注入
这种方式注入属性时,类中必须要有相应的构造方法
在bean标签中,加入<constructor-arg></constructor-arg>
标签,
该标签的name属性表示构造方法的参数名,index属性表示构造方法的参数索引。
赋值时,原始类型和字符串用value,引用类型用ref。
<!--注入Person类对象并用构造方法注入其属性-->
<bean class="com.hqyj.spring01.Person" id="p2"><!--constructor-arg表示构造方法参数 name是参数名 index是参数索引--><constructor-arg name="name" value="张明"></constructor-arg><constructor-arg index="1" value="20"></constructor-arg><constructor-arg name="car" ref="c"></constructor-arg>
</bean>
复杂属性注入
/*
* 定义电影类
* */
public class Movie {//电影名private String movieName;//导演private String director;//时长private int duration;//主演private List<String> playerList;//类型private String movieType;//放映时间,最终格式为yyyy/MM/dd HH:mm:ssprivate String showTime;
}
List类型的属性
<!--注入Movie对象-->
<bean class="com.hqyj.spring01.Movie" id="movie1"><property name="movieName" value="夏洛特烦恼"></property><property name="director" value="闫非、彭大魔"></property><property name="duration" value="87"></property><!--List类型属性赋值--><property name="playerList" ><!--使用list标签--><list><!--如果集合中保存的是引用类型,使用ref标签--><!--如果集合中保存的是原始类型或字符串,使用value标签--><value>沈腾</value><value>艾伦</value><value>马丽</value></list></property><property name="movieType" value="喜剧"></property><property name="showTime" value="2010/06/01 0:0:0"></property>
</bean>
Set类型的属性
<!--注入PetShop对象-->
<bean class="com.hqyj.spring01.test3.PetShop" id="petShop"><property name="shopName" value="xxx宠物店"></property><property name="petSet"><!--Set类型的属性--><set><!--如果中保存的是原始类型或字符串,使用value子标签--><!--如果保存的是引用类型,使用ref子标签加bean属性设置对应的id--><ref bean="p1"></ref><ref bean="p2"></ref><ref bean="p3"></ref></set></property>
</bean>
Map类型的属性
<!--注入Cinema对象-->
<bean class="com.hqyj.spring01.Cinema" id="cinema"><property name="name" value="万达影城"></property><property name="timeTable"><!--Map类型属性赋值,标明键和值的类型--><map key-type="java.lang.Integer" value-type="com.hqyj.spring01.Movie"><!--entry标签表示键值对 如果键值对都是原始类型或字符串,使用key和value--><!--如果键值对中有引用类型,使用key-ref或value-ref--><entry key="1" value-ref="movie1"></entry><entry key="2" value-ref="movie2"></entry></map></property>
</bean>
属性自动注入autowire
以上所有案例中,如果要在A对象中注入一个引用类型的对象B,都是手动将对象B注入到对象A中。
如在Person中注入Car对象,在Cinema中注入Movie等。
这种情况下,如果当某个被注入的bean的id更改后,所有引用了该bean的地方都要进行修改。
所以将手动注入更改为自动注入(自动装配),就无需添加相应的<property>
标签,甚至可以无需定义bean的id。
实现自动注入
在某个bean标签中,加入autowire属性,设置值为"byName"或"byType"。通常设置为"byType"。
autowire属性的值
byType
- 类中要有被注入的属性的setter()方法
- 被自动注入的对象可以没有id
- Spring容器中,某个对象的类型要与该setter()方法的参数类型一致,且容器中只有一个该类型的对象。
- 如setCar(Car c),Spring就会自动在容器中寻找类型为Car的对象自动装配
byName
- 类中要有被注入的属性的setter()方法
- 被自动注入的对象必须要有id
- 实际是根据setXXX()方法set后的单词XXX关联
- 如setCar(Car c),Spring就会自动在容器中寻找id为car的对象自动装配
在Web项目中,可以利用自动装配,在控制层中自动装配业务逻辑层的对象,在业务逻辑层中自动装配数据访问层的对象。
在作业练习中,controller、dao都需要setter方法,再在spring配置文件中配置autowire后,才能实现自动装配。
如果使用了注解,就无需在类中添加setter方法,spring配置文件中也无需设置autowire。
Spring核心注解
在Spring配置文件中加入
<!--设置要扫描的包,扫描这个包下所有使用了注解的类-->
<context:component-scan base-package="com.hqyj.spring02.bookSystem"></context:component-scan>
类上加的注解
- @Component
- 当一个类不好归纳时,定义为普通组件
- @Controller
- 定义一个类为控制层组件
- @Service
- 定义一个类为业务层组件
- @Repository
- 定义一个类为持久层(数组访问层)组件
- @Lazy/@Lazy(value=true)
- 设置该类为懒加载。
- @Scope(value=“singleton/prototype”)
- 设置为单例/原型模式。
说明
以上注解公共特点
- 都是将对应类的对象注入到Spring容器中,用于替换配置文件中的bean标签
- 都默认是单例模式非懒加载
- 默认注入的对象id为当前类的类名首字母小写形式
- 如在BookDao类上添加,id默认为bookDao
- 可以通过注解的value属性自定义注入的对象的id名,如@Component(value=“key”)表示注入的对象id为key
属性上加的注解
@Autowired
优先使用byType方式从Spring容器中获取对应类型的对象自动装配。先检索Spring容器中对应类型对象的数量,如果数量为0直接报错;数量为1直接装配
数量大于1,会再尝试使用byName方式获取对应id的对象,但要配合@Qualifier(value=“某个对象的id”)一起使用,指定id进行装配
@Qualifier(value=“某个对象的id”)
- 配合@Autowired注解,使用byName方式获取某个对象id的bean进行装配
@Resource(name=“某个对象的id”)
该注解相当于@Autowired+@Qualifier(value=“某个对象的id”)
优先使用byName方式,从Spring容器中检索name为指定名的对象进行装配,如果没有则尝试使用byType方式,要求对象有且只有一个,否则也会报错。
说明
如果要在某个类中使用Spring容器中的某个对象时,只需定义成员变量,无需创建对象,通过@Autowired或@Resource注解进行自动装配
实际开发中,绝大部分情况下,需要自动装配对象有且只有一个,并且命名规范,所以@Autowired或@Resource区别不是很大。@Autowired优先使用byType方式,@Resource优先使用byName方式
如果@Resource不能使用,是因为缺少javax.annotation包,需要引入对应依赖
<dependency><groupId>javax.annotation</groupId><artifactId>javax.annotation-api</artifactId><version>1.3.2</version> </dependency>
在Web项目中使用Spring
1.创建基于Maven的web-app项目
2.添加依赖
<!--servlet-->
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version>
</dependency>
<!--spring容器-->
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.23</version>
</dependency>
<!--web集成spring-->
<dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.3.23</version>
</dependency>
3.在main目录下创建java和resources目录,修改web.xml版本为4.0
4.在resources目录下创建Spring配置文件application.xml,扫描使用了注解的根包
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!--扫描使用了Spring注解的根包--><context:component-scan base-package="com.hqyj.springweb"></context:component-scan>
</beans>
5.创建一个类,使用@Componet注解将其注入到Spring容器中
package com.hqyj.springweb.entity;import org.springframework.stereotype.Component;@Component
public class Pojo {public void fun(){System.out.println("hello springweb!");}
}
如何初始化Spring容器(解析Spring配置文件)
在控制台应用程序中,可以在main方法中通过ClassPathXmlApplicationContext来解析Spring配置文件,初始化Spring容器。
在web项目中没有main方法,只有servlet中的service方法,如果在service方法中创建ClassPathXmlApplicationContext对象,会每次访问都执行。
而Spring容器只需初始化一次,在项目启动时就解析Spring配置文件,全局监听器就是一个很好的选择。
spring-web包中提供了一个ContextLoaderListener类,它实现了ServletContextListener,属于项目级别的全局监听器。
这个类需要一个contextConfigLocation参数,表示要解析的Spring配置文件的路径。
这个监听器会在项目启动时,读取指定的Spring配置文件路径,并且创建WebApplicationContext对象,即Spring容器。
6.在web.xml中配置监听器用于初始化Spring容器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!--配置监听器ContextLoaderListener--><listener><!--监听器全限定名--><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!--定义全局参数contextConfigLocation用于读取Spring配置文件--><context-param><!--参数名固定contextConfigLocation--><param-name>contextConfigLocation</param-name><!--只是Spring配置文件的路径 classpath:表示从根目录出发--><param-value>classpath:application.xml</param-value></context-param>
</web-app>
7.创建一个Servlet,访问该Servlet,获取Spring容器,从容器中获取注入的对象
package com.hqyj.springweb.controller;import com.hqyj.springweb.entity.Pojo;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebServlet("/hello")
public class MyServlet extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//获取Spring容器WebApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(getServletContext());//从容器中获取某个beanPojo pojo = app.getBean("pojo", Pojo.class);pojo.fun();}
}
JDBCTemplate常用方法
方法 | 作用 | 说明 |
---|---|---|
query(String sql,RowMapper mapper) | 无条件查询 | 返回值为List集合 |
update(String sql) | 无条件更新(删除、修改) | 返回值为受影响的行数 |
query(String sql,RowMapper mapper,Object… objs) | 条件查询 | 可变参数为?的值 |
update(String sql,Object… objs) | 条件更新(增加、删除、修改) | 可变参数为?的值 |
queryForObject(String sql,RowMapper mapper) | 无条件查询单个对象 | 返回值为指定对象 |
queryForObject(String sql,RowMapper mapper,Object… objs) | 条件查询单个对象 | 返回值为指定对象 |
execute(String sql) | 执行指定的sql | 无返回值 |
MVC
MVC设计思想并不是某个语言特有的设计思想,而是一种通用的模式。
是将一个应用分为三个组成部分:Model模型,View视图,Controller控制器
这样会降低系统的耦合度,提高它的可扩展性和维护性。
SpringMVC
在Web阶段中,控制层是由Servlet实现,传统的Servlet,需要创建、重写方法、配置映射。使用时极不方便,SpringMVC可以替换Servlet。
SpringMVC是Spring框架中位于Web开发中的一个模块,是Spring基于MVC设计模式设计的轻量级Web框架。
SpringMVC提供了一个DispatcherServlet的类,是一个Servlet。它在指定映射(通常设置为/或*.do)接收某个请求后,调用相应的模型处理得到结果,再通过视图解析器,跳转到指定页面,将结果进行渲染。
原理大致为:配置SpringMVC中的DispatcherServlet,将其映射设置为/或.do。*
如果是/表示一切请求先经过它,如果是*.do表示以.do结尾的请求先经过它,
它对该请求进行解析,指定某个Controller中的某个方法,这些方法通常返回一个字符串,
这个字符串是一个页面的名称,再通过视图解析器,将该字符串解析为某个视图的名称,跳转到该视图页面。
详细流程
使用SpringMVC
1.创建webapp项目
- 修改web.xml版本为4.0
- 创建java和resources目录
- 创建包结构
2.添加依赖
<!-- spring-webmvc -->
<!-- 这个依赖会包含spring-web和spring-context -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.23</version>
</dependency>
3.配置初始化Spring
在resources目录下创建Spring配置文件application.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!--设置扫描使用了注解的根包--><context:component-scan base-package="com.hqyj.springmvc"></context:component-scan> </beans>
在web.xml中使用监听器ContextLoaderListener初始化Spring
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!--配置全局监听器初始化Spring--><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!--定义全局参数读取Spring配置文件--><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:application.xml</param-value></context-param> </web-app>
4.配置SpringMVC
在resources目录下创建配置SpringMVC的配置文件springmvc.xml
- 配置要扫描的控制层类所在的包名
- 配置内部资源视图解析器以及视图路径的前后缀
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!--扫描控制层所在的包--><context:component-scan base-package="com.hqyj.springmvc.controller"></context:component-scan><!--配置内部资源视图解析器--><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!--最终控制层跳转的页面所在的路径及页面自身后缀名--><!--jsp页面不建议直接通过浏览器访问。在WEB-INF目录下在资源,无法通过浏览器直接方法,所以将jsp保存在WEB-INF目录下,最好创建一个pages--><property name="prefix" value="/WEB-INF/pages/"></property><!--现阶段使用jsp输出数据,所以后缀为.jsp--><property name="suffix" value=".jsp"></property></bean> </beans>
在web.xml中配置DispatcherServlet
- 将该Servlet的请求映射设置为/,表示所有请求都会访问该Servlet,由该Servlet再进行分发
<!--配置DispatcherServlet--> <servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--设置该Servlet的初始化参数,用于读取SpringMVC配置文件--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param> </servlet> <servlet-mapping><servlet-name>dispatcherServlet</servlet-name><!--设置该servlet的映射为/或*.do--><url-pattern>/</url-pattern> </servlet-mapping>
5.在WEB-INF目录下创建一个pages目录,在其中创建一个welcome.jsp页面
- 通常jsp页面不允许被浏览器直接访问,需要保存在WEB-INF目录下
6.编写控制层代码
在controller包下创建一个类,加上@Controller注解
该类中定义的方法方法加入@RequestMapping()注解表示访问该方法的映射
该类中定义的方法返回值通常为字符串,表示某个页面的名称,也可以是另一个controller中的方法映射名
package com.hqyj.springmvc.controller;import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;//加入@Controller注解表示该类是一个控制层类,替换之前的servlet @Controller //该注解如果只设置请求映射,直接填字符串 @RequestMapping("/first") public class HelloController {//该注解如果还有其他参数要设置,路径用path赋值@RequestMapping(path="/hello")public String hello(){//返回的字符串是某个页面的名称或另一个控制层中方法的请求映射return "welcome";} }
将项目部署到tomcat后,访问http://localhost:8080/SpringMVC_war_exploded/first/hello,即可跳转到指定页面
SpringMVC相关注解
@Controller
- 只能写在类上,表示该类属于一个控制器
@RequestMapping(“/请求映射名”)/@RequestMapping(value=“/请求映射名”)/@RequestMapping(path=“/请求映射名”)
- 该注解可以写在类或方法上。写在类上用于区分功能模块,写在类上用于区分具体功能
- 默认写一个属性或value或path后的值,都表示访问该类或该方法时的请求映射
@RequestMapping(value=“/请求映射名”,method=RequestMethod.GET/POST/PUT/DELETE)
- method属性表示使用哪种请求方式访问该类或该方法
- 如果注解中不止一个属性,每个属性都需要指定属性名
**@GetMapping(“/请求映射名”)**相当于@RequestMapping(value=“/请求映射名”,method=RequestMethod.GET)
- post、put、delete同理
- @GetMapping只能写在方法上
@PathVariable
该注解写在某个方法的某个形参上
通常配合@RequestMapping(“/{path}”)获取请求时传递的参数
@RequestMapping("/{path}") public String fun(@PathVariable("path") String pageName){return pageName; } //当前方法如果通过"localhost:8080/项目名/hello"访问,就会跳转到hello.jsp //当前方法如果通过"localhost:8080/项目名/error"访问,就会跳转到error.jsp //映射中的/{path}就是获取路径中的hello或error,将其赋值给形参 //通常用于跳转指定页面
@RequestParam(value=“传递的参数名”,defaultValue =“没有传递参数时的默认值”)
- 该注解写在某个方法的某个参数上
- 用于获取提交的数据,可以设置默认值在没有提交数据时使用
配置Spring+SpringMVC时用到的关键类
在web.xml中配置Spring全局监听器
ContextLoaderListener
<listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:application.xml</param-value> </context-param>
在Springmvc配置文件中配置SpringMVC内部资源视图解析器
InternalResourceViewResolver
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/pages/"></property><property name="suffix" value=".jsp"></property> </bean>
在web.xml中配置SpringMVC请求分发Servlet
DispatcherServlet
<servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param> </servlet><servlet-mapping><servlet-name>dispatcherServlet</servlet-name><url-pattern>/</url-pattern> </servlet-mapping>
在web.xml中配置字符编码过滤器
CharacterEncodingFilter
<filter><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>utf-8</param-value></init-param> </filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern> </filter-mapping>
SpringBoot
Spring推出的一个Spring框架的脚手架。
不是一个新的框架,而是搭建Spring相关内容框架的平台。
它省去了Spring、SpringMVC项目繁琐的配置过程,让开发变得更加简单。
本质还是Spring+SpringMVC,可以搭配其他的ORM框架,如MyBatis、MyBatisPlus、JPA、Hibernate等。
特点
- 内置了Tomcat服务器,不需要部署项目到Tomcat中
- 内置了数据源Hikari
- 减少了jar文件依赖的配置
- SpringBoot中的配置文件可以使用yml格式文件,代替properties或xml
创建SpringBoot项目
通过IDEA创建
通过官网模板创建
官网模板https://start.spring.io/
点击生成,会下载一个压缩文件,解压后通过IDEA打开。
无论哪种方式,都需要重写设置Maven配置文件
创建成功后的目录结构
第一个springboot项目的helloworld
热部署
项目在开发过程中,可以不需要每次都重启,等待一段时间后会自动更新编译运行
使用
添加依赖,可以在创建的项目的时候选择,也可以中途添加
<!--热部署-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><version>2.7.8</version>
</dependency>
开启热部署
Lombok
用于简化实体类中模板代码的工具
使用
添加依赖,可以在创建的项目的时候选择,也可以中途添加
<!--Lombok-->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version><scope>provided</scope>
</dependency>
安装插件(IDEA2020.2之后的版本会内置Lombok插件,无需安装)
IDEA插件官网Versions: Lombok - IntelliJ IDEs Plugin | Marketplace (jetbrains.com)
IDEA内置插件市场搜索
在某个实体类上添加注解
lombok常用注解 | 作用 |
---|---|
@AllArgsConstructor | 自动生成全参构造方法 |
@Data | 以下注解之和 |
@Setter | 自动生成set方法 |
@Getter | 自动生成get方法 |
@NoArgsConstructor | 自动生成无参构造方法 |
@ToString | 自动生成toString方法 |
@EqualsAndHashcode | 自动生成equals和hashcode方法 |
SpringBoot+MyBatis实现单表查询
1.创建好SpringBoot项目
最好在创建的时候选择以下依赖
- spring-web(必选)
- lombok
- spring-devtools
- springboot集成mybatis
- mysql驱动
都可以后续添加
<!--web-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency><!--热部署-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><version>2.7.8</version>
</dependency><!--Lombok-->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version><scope>provided</scope>
</dependency>
2.在pom.xml中添加mybatis集成SpringBoot依赖和数据库驱动
<!--mysql-->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.31</version>
</dependency>
<!--springboot集成MyBatis-->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.3.0</version>
</dependency>
3.在springboot配置文件application.properties中
#注释
#.properties文件称为属性文件,数据以键值对"键=值"的形式保存
#设置项目启动端口号
#server.port=9090
#设置项目上下文路径
#server.servlet.context-path=/springbootday1#mybatis相关配置
#开启驼峰命名映射
mybatis.configuration.map-underscore-to-camel-case=true
#打印sql语句
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#扫描mybatis的sql映射文件(将mapper.xml文件保存在resources目录下的mapper目录下)
mybatis.mapper-locations=classpath:mapper/*.xml#数据库信息
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/gamedb?serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
mybatis的sql映射文件模板
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--设置该文件对应的dao层接口全限定名-->
<mapper namespace=""></mapper>
4.根据数据表创建实体类、dao层接口、service、controller
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tfTkKQ79-1676799463202)(day10-SpringBoot+MyBatis1.assets/image-20230203154807705.png)]
Hero
@Data
public class Hero{private Integer id;private String name;private String position;private String sex;private Double price;private String shelfDate;
}
dao
@Repository
public interface HeroDao{List<Hero> queryAll();
}
mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--设置该文件对应的dao层接口全限定名-->
<mapper namespace="com.xxx.dao.HeroDao"><select id="queryAll" resultType="com.xxx.entity.Hero">select * from hero</select>
</mapper>
service
@Service
public class HeroService{@Autowiredprivate HeroDao heroDao;public List<Hero> queryAll(){return heroDao.queryAll(); }
}
controller
@Controller
@RequestMapping("/hero")
public class HeroController{@Autowiredprivate HeroService heroService;@RequestMapping("/queryAll")@ResponseBodypublic List<Hero> queryAll(){return heroDao.queryAll(); }
}
5.在SpringBoot的启动类上,加入@MapperScan注解,扫描dao层所在根包
@SpringBootApplication
//扫描dao层所在的根包
@MapperScan("com.hqyj.first.dao")
public class FirstApplication {public static void main(String[] args) {SpringApplication.run(FirstApplication.class, args);}}
启动项目,按自定的项目上下文路径和端口号访问某个controller中的方法
MyBatisPlus
官网简介 | MyBatis-Plus (baomidou.com)
MyBatis-Plus (简称 MP)是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
只需简单的配置,就能实现对单表的CURD。
其核心有两个接口:BaseMapper和IService
BaseMapper中封装了大量数据访问层的方法
IServcie中封装了大量业务流程层的方法
SpringBoot+MyBatisPlus
1.创建SpringBoot项目
创建时勾选依赖
- devtools
- lombok
- spring-web
- mysql-driver
2.导入SpringBoot集成MyBatisPlus依赖
<!-- SpringBoot集成MyBatisPlus -->
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.1</version>
</dependency>
3.配置application.properties文件
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/gamedb?serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root# 开启sql日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 无需加入开启驼峰命名映射,MyBatisPlus默认使用驼峰命名进行属性-字段映射
#mybatis-plus.configuration.map-underscore-to-camel-case=true
4.根据数据表创建实体类
实体类的属性名命名方式:
- MyBatisPlus默认使用驼峰命名对字段和属性进行映射。如将字段stu_name对应的属性写为stuName
- 如果字段名和属性名不一致,在属性名上加入**@TableField(value = “字段名”)**
- 主键字段对应的属性,需要加入@TableId注解,其type属性表示主键生成策略
- @TableId(type = IdType.AUTO)表示主键自增,在数据库也要将主键设置为自增
- @TableId(type = IdType.ASSIGN_ID)//IdType.ASSIGN_ID表示使用"雪花算法"(根据时间和机器特征码)生成一个id
- @TableId(type = IdType.ASSIGN_UUID)//IdType.ASSIGN_UUID表示使用UUID生成一个随机字符串id
@Data
public class Hero {//type表示主键生成策略,@TableId(type = IdType.AUTO)// IdType.AUTO表示主键自增,在数据库也要将主键设置为自增//@TableId(type = IdType.ASSIGN_ID)//IdType.ASSIGN_ID表示使用"雪花算法"(根据时间和机器特征码)生成一个id//@TableId(type = IdType.ASSIGN_UUID)//IdType.ASSIGN_UUID表示使用UUID生成一个随机字符串idprivate Integer id;//如果属性名和字段名不一致@TableField(value = "name")private String heroName;private String position;private String sex;private Integer price;private String shelfDate;
}
5.编写数据访问层接口
可以不用写@Repository,继承BaseMapper接口,设置泛型
/*
* 数据访问层可以称为dao或mapper层
* 可以不用加@Repository注解
* */
public interface HeroMapper extends BaseMapper<Hero> {}
6.在SpringBoot的启动类中,扫描数据访问层所在包
@SpringBootApplication
@MapperScan("com.hqyj.sbmp01.mapper")
public class Sbmp01Application {public static void main(String[] args) {SpringApplication.run(Sbmp01Application.class, args);}
}
测试
在SpringBoot自带的单元测试类中,注入HeroMapper对象,调用BaseMapper中定义的方法即可实现CURD。
BaseMapper接口
BaseMapper接口中定义了常用的增删改查方法,
在数据访问层接口中继承该接口
方法列表
使用
public interface HeroMapper extends BaseMapper<Hero> {}
BaseMapper接口中的常用方法
方法名 | 参数 | 作用 |
---|---|---|
selectList(Wrapper wrapper) | 条件构造器 | 根据条件查询集合,如果实参为null表示查询所有,返回List集合 |
selectById(Serializable id) | 主键 | 根据主键查询单个对象,返回单个对象 |
selectOne(Wrapper wrapper) | 条件构造器 | 条件查询单个对象,返回单个对象 |
insert(T entity) | 实体对象 | 添加单个实体 |
updateById(T entity) | 实体对象 | 根据实体对象单个修改,对象必须至少有一个属性和主键 |
update(T entity,Wrapper wrapper) | 实体对象和条件构造器 | 根据条件修改全部,对象必须至少有一个属性 |
deleteById(Serializable id/T entity) | 主键/实体对象 | 根据主键删除单个对象 |
deleteBatchIds(Collection ids) | 主键集合 | 根据集合删除 |
delete(Wrapper wrapper) | 条件构造器 | 根据条件删除,如果实参为null表示无条件删除所有 |
IService接口
IService接口减少业务逻辑层的代码,并对BaseMapper进行了拓展
在业务流程类中继承该接口
部分方法列表
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B3FKV7kI-1676799562750)(SpringBoot+MyBatisPlus.assets/image-20230208172729669.png)]
使用
1.创建一个业务层接口,继承IService接口,设置泛型
/* * 创建业务逻辑层接口,继承IService<T>接口,设置泛型 * */ public interface HeroService extends IService<Hero> {}
2.创建一个业务层接口的实现类,添加@Service注解,继承 ServiceImpl<M, T>,实现上一步创建的接口
- M是数据访问层接口
- T是实体类
/* * 1.添加@Service * 2.继承ServiceImpl<M, T> M是Mapper类 T是实体类 * 3.实现自定义Service接口 * */ @Service public class ImpHeroService extends ServiceImpl<HeroMapper, Hero> implements HeroService {}
IService接口中的常用方法
方法 | 作用 |
---|---|
list() | 无条件查询所有 |
list(Wrapper wrapper) | 条件查询素有 |
page(Page page) | 无条件分页查询,Page是分页模型对象 |
page(Page page,Wrapper wrapper) | 条件分页查询,Page是分页模型对象 |
getById(Serializable id) | 根据主键查询单个对象 |
getOne(Wrapper wrapper) | 条件查询单个对象 |
save(T entity) | 添加单个对象 |
save(Collection col) | 批量添加对象的集合 |
updateById(T entity) | 修改,参数至少有一个属性值和主键 |
saveOrUpdate(T entity) | 添加或修改。如果实参对象的主键值不存在则添加,存在则修改 |
update(T entity,Wrapper wrapper) | 条件修改,条件为null则修改全部数据 |
removeById(Serializable id/T entity) | 根据主键或包含主键的对象删除 |
removeBatchByIds(Collection ids) | 根据集合删除 |
remove(Wrapper wrapper) | 根据条件删除,条件为null则删除全部 |
条件构造器Wrapper
BaseMapper和IService接口中有很多方法都有这个参数,表示一个条件构造器对象。
如果该参数实际传递的值为null,表示没有任何条件,
这个Wrapper是一个抽象类,如果想要带条件,就要创建一个该类的子类对象。
常用子类为QueryWrapper和UpdateWrapper,
查询是创建QueryWrapper对象,更新时创建UpdateWrapper,实际使用无区别。
Wrapper对象带参数
Wrapper<T> wrapper = new QueryWrapper(T entity);
QueryWrapper<T> wrapper = new QueryWrapper(T entity);
Wrapper构造方法的参数如果是一个实体对象,只要该对象的属性不为空,就会将所有属性用and拼接起来作为条件。
这种适合已知某个字段为某个值时使用。
@Test
void test1() {//创建实体对象,只带两个属性值Hero hero = new Hero();hero.setHeroName("瑞兹");hero.setSex("女");//创建一个带实体参数的条件构造器对象Wrapper<Hero> wrapper = new QueryWrapper<>(hero);System.out.println(heroService.getOne(wrapper));
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TecENI03-1676799641575)(day14-SpringBoot+MyBatisPlus2.assets/image-20230209095105726.png)]
Wrapper对象不带参数
Wrapper<T> wrapper = new QueryWrapper();
QueryWrapper<T> wrapper = new QueryWrapper();
当条件构造器不带参数时,就需要自定义条件。
这种适用于自定义查询条件。
默认多个条件时,用and连接,如果条件之间要使用or,调用or()方法
(“position”,“count(id)”),对应的sql查询部分为select “position”,“count(id)” from hero
分页查询
MyBatisPlus中集成了分页功能,只需在项目的启动类中注入一个分页拦截器对象
/*注入一个MyBatisPlus提供的分页拦截器对象定义一个方法,在方法上加入@Bean注解,将该方法的返回值注入到Spring容器中*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){//创建一个MybatisPlus拦截器对象MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//通过拦截器对象添加分页拦截器对象,设置数据库类型interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;
}
@Test
void test1(){//无条件分页查询page(Page pageInfo)//1.创建一个分页模型对象,设置泛型,参数为当前页和每页显示的记录数Page<Hero> pageInfo = new Page<>(1, 5);//2.调用IService中的page方法,参数为分页模型对象,返回值也是该对象pageInfo = heroService.page(pageInfo);//分页的相关信息都保存在分页模型对象pageInfo中System.out.println("总页数"+pageInfo.getPages());System.out.println("当前页"+pageInfo.getCurrent());System.out.println("每页显示的记录数"+pageInfo.getSize());System.out.println("总记录数"+pageInfo.getTotal());System.out.println("分页后的集合"+pageInfo.getRecords());System.out.println("是否有下一页"+pageInfo.hasNext());System.out.println("是否有上一页"+pageInfo.hasPrevious());//条件分页page(Page pageInfo,Wrapper wrapper)//分页查询所有法师pageInfo= heroService.page(pageInfo,new QueryWrapper<Hero>().eq("position","法师"));pageInfo.getRecords().forEach(System.out::println);
}
代码生成器
MyBatisPlus中用于自动生成entity、mapper、service、controller这些类和接口的工具
1.添加依赖
<!-- 代码生成器 -->
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.3</version>
</dependency>
<!--代码生成器所需引擎-->
<dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifactId><version>2.3</version>
</dependency>
2.代码生成器类
修改以下几处
- 数据库信息
- 输出目录为本地硬盘目录
- 父包名
- 要生成的表名
package com.hqyj.question_sys.util;import com.baomidou.mybatisplus.generator.FastAutoGenerator;public class CodeGenerator {public static void main(String[] args) {//***数据库的url, 用户名和密码FastAutoGenerator.create("jdbc:mysql://localhost:3306/question_sys?serverTimezone=Asia/Shanghai","root", "root").globalConfig(builder -> {builder.author("HQYJ") // 设置作者,生成文件的注释里的作者.outputDir("F:\\框架\\question_sys\\src\\main\\java"); //***指定输出目录}).packageConfig(builder -> {builder.parent("com.hqyj.question_sys"); //***设置父包名// .controller("controller") //控制层包名// .service("service") //service接口包名// .serviceImpl("service.impl") //service接口实现包名// .mapper("mapper") //mapper接口包名// .xml("mapper.xml") //映射文件的包名(如果要生成的话,加上这句,去掉下面的.xml方法)// .entity("entity"); //实体类的包名}).strategyConfig(builder -> {builder.addInclude("question_catalog","question") //***设置需要生成的表名.controllerBuilder();//只生成Controller//.enableRestStyle(); //生成的Controller类添加@RestController;}).templateConfig(builder -> {builder.xml(null); //禁止生成xml映射文件}).execute();}
}
运行该类即可自动生成
Thymeleaf
SpringBoot官方建议使用的页面模板引擎,代替之前的JSP。
它是以HTML为基础,可以展示静态数据,方便前端人员开发静态页面,
也可以通过Thymeleaf的语法,配合EL输出由控制器跳转而来的动态数据。
Thymeleaf从入门到精通 - 知乎 (zhihu.com)
用法
1.添加依赖
<!--thymeleaf页面模板引擎-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId><version>2.7.3</version>
</dependency>
2.在temlates目录下创建一个HTML页面
在页面的HTML标签中,加入xmlns:th="http://www.thymeleaf.org"
属性。
可以通过修改IDEA中的HTML页面模板,之后每次创建HTML页面都会有该属性
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o0Rj2ENQ-1676799641577)(day14-SpringBoot+MyBatisPlus2.assets/image-20230209143658152.png)]
3.thymeleaf具体使用
双标签中的输出变量: th:text
<h1 th:text="${作用域中某个对象名}"></h1><h1 th:text="${username}"></h1>
单标签中设置value的值:th:value
<input type="text" th:value="${作用域中某个对象名}"><input type="text" th:value="${变量.属性名}">
遍历:th:each
<table><tr th:each="变量:${作用域中的集合名}"><td th:text="${变量.属性名}"></td></tr> </table><table><tr th:each="hero:${heroList}"><td th:text="${hero.id}"></td><td th:text="${hero.name}"></td><td th:text="${hero.sex}"></td></tr> </table>
超链接获取全局路径:th:href=“@{/}”
不带参数
<link th:href="@{/bootstrap-3.4.1-dist/css/bootstrap.css}" rel="stylesheet">
带参数
<a th:href="@{'/hero/delete?id='+${hero.id}">删除</a><a th:href="@{/question/findById(id=${question.quesCode})}">编辑</a>
表单提交路径:th:action=“@{/}”
<form methos="post" th:action="@{/hero/insert}"></form>
判断:th:if
<h1 th:if="判断逻辑">用户信息</h1><h1 th:if="${userinfo.username==null}">请登录</h1>
选中单选按钮或复选框:th:checked
<input type="radio" value="男" name="sex" th:checked="逻辑判断"><input type="radio" value="男" name="sex" th:checked="${user.sex=='男'}">男 <input type="radio" value="女" name="sex" th:checked="${user.sex eq '女'}">女
选中下拉菜单:th:selected
<select><option th:selected="逻辑判断"></option> </select><select><option th:selected="${book.typeId==bookType.typeId}" th:each="bookType:${list}" th:value="${bookType.typeId}" th:text="${bookType.typeName}"></option> </select>
src属性:th:src
<script th:src="@{/bootstrap-3.4.1-dist/js/jquery-3.6.2.min.js}"></script>
内联表达式
Thymeleaf页面中使用[[]]可以在script标签中使用EL表达式,这两对中括号拼接的内容称为内联表达式。
在给script标签加入**th:inline=“javascript”**后使用
<script th:inline="javascript">$(function () {//遍历页码$(".pno").each(function (){//如果页码和当前页一致,高亮显示if($(this).text()==[[${pageInfo.current}]]){$(this).addClass("active");}});}); </script><script th:inline="javascript">$(function () {//使用ajax读取所有的题目类型对象,遍历成option$.ajax({url:[[@{/qc/queryAll}]],success:function (res){for(var i=0;i<res.length;i++){let qcId = res[i].qcId;let qcName = res[i].qcName;$("<option></option>").text(qcName).val(qcId).appendTo($("select[name=qcId]"));}}});}); </script>
Spring Data JPA
2001年推出了Hibernate,是一个全自动ORM框架。可以不用编写SQL语句,就能实现对数据库的持久化操作。
SUN公司在Hibernate的基础上,制定了JPA,全称 Java Persisitence API,中文名Java持久化API,
是一套Java访问数据库的规范,由一系列接口和抽象类构成。
后来Spring团队在SUN公司制定的JPA这套规范下,推出了Spring Data JPA,是JPA的具体实现。
如今常说的JPA,通常指Spring Data JPA。
SpringBoot集成Spring Data JPA
1.创建SpringBoot项目,选择依赖
2.编辑配置文件,设置要连接的数据库信息
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/bookdb?serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root# 设置数据库类型
spring.jpa.database=mysql
# 打印SQL语句
spring.jpa.show-sql=true
3.创建实体类
类上加**@Entity**注解
主键属性上加
@Id注解标明主键
**@GeneratedValue(strategy = GenerationType.IDENTITY)**设置MySQL数据库主键生成策略,数据库设置为自增
其他属性名与字段名一致或驼峰命名法
- 如果字段名多个单词之间用_,使用驼峰命名法
- 如果不相同,使用**@Column(name=“字段名”)**注解指定该属性对应的字段名
@Data
@Entity
/*
* 实体类的属性名建议使用驼峰命名法
* */
public class BookInfo {@Id//主键字段//主键生成策略,GenerationType.IDENTITY表示MySQL自增@GeneratedValue(strategy = GenerationType.IDENTITY)private Integer bookId;private Integer typeId;private String bookName;private String bookAuthor;//如果字段名和属性名不一致,使用@Column指定字段名@Column(name = "book_price")private Integer price;private Integer bookNum;private String publisher_date;
}
4.数据访问层接口
- 类上加@Repository注解
- 继承JpaRepository<实体类型,主键类型>接口
@Repository
public interface BookInfoDao extends JpaRepository<BookInfo,Integer> {}
5.测试常用方法
方法名 | 返回值 | 作用 |
---|---|---|
findAll() | List | 查询所有数据。 |
save(T entity) | T entity | 添加或修改。如果不存在主键属性或主键值不存在,执行添加;如果存在主键属性且有该主键值,执行修改。 |
delete(T entity) | void | 根据对象删除。如果该对象中有主键属性且有该主键值,根据该主键值删除。 |
findById(主键) | Optional | 根据主键值查询。返回的对象调用isPresent()结果为true,表示查询到了数据,继续调用get()得到查询到的对象。 |
JPA进阶
分页查询
调用数据访问层中的**findAll(Pageable pageable)**方法,即可实现分页。
参数Pageable是org.springframework.data.domain包中的一个接口,通过其实现类
PageRequest,调用静态方法of(int page,int size),当做Pageable对象使用。
这里的page从0开始为第一页。
@Test
void queryByPage(){//PageRequest是Pageable的实现类,调用静态方法of(int page,int size)//这里的page的值0表示第一页//调用findAll(Pageable pageable)方法,返回分页模型对象Page<BookInfo> pageInfo = bookInfoDao.findAll(PageRequest.of(0,5));//分页相关数据System.out.println("总记录数"+pageInfo.getTotalElements());System.out.println("最大页数"+pageInfo.getTotalPages());System.out.println("分页后的数据集合"+pageInfo.getContent());System.out.println("当前页数"+pageInfo.getNumber());System.out.println("每页显示的记录数"+pageInfo.getSize());System.out.println("是否还有下一页"+pageInfo.hasNext());System.out.println("是否还有上一页"+pageInfo.hasPrevious());
}
条件查询
在JPA中,使用自定义方法名自动生成对应的SQL语句,实现条件查询。
如在dao中定义了queryById(int id)方法,就表示根据id查询,自动生成sql语句。
方法命名格式
[xxx] [By] [字段对应的属性名] [规则] [Or/And] [字段对应的属性名] [规则] …
- **xxx可以是find、get、query、search
- 方法如果有参数,参数的顺序和方法名中的参数顺序一致
如findByBookNameAndBookAuthor(String bookName,String bookAuthor),
对应的sql语句为 select * from book where book_name =? and book_author=?
常用规则
规则 | 方法名 | SQL中的条件 |
---|---|---|
指定值 | findByBookName(String name) | book_name = name |
Or/And | findByBookNameOrBookAuthor(String name,String author) | book_name = name or book_author = author |
After/Befor | findByBookPriceAfter(double price) | book_price > price |
GreaterThanEqual/LessThanEqual | findByBookNumLessThanEqual(int num) | book_num <= num |
Between | findByBookNumBetween(int min,int max) | book_num between min and max |
Is[Not]Null | findByPublisherDateIsNull() | publish_date is null |
[Not]Like | findByBookNameLike(String condition) | book_name like ‘condition’ |
[Not]Contains | findByBookNameContains(String keyword) | book_name like ‘%keyword%’ |
StartsWith/EndsWith | findByBookNameStartsWith(String firstName) | book_name like ‘firstName%’ |
无条件排序:findAllByOrderBy字段[Desc/Asc] | findAllByOrderByBookId() | order by book_id asc |
有条件排序:findAllBy条件OrderBy字段[Desc/Asc] | findAllByTypeIdOrderByBookIdDesc() | type_id = ? order by book_id desc |
条件分页查询
只需在定义方法时,将方法的返回值设置为Page类型,在参数中就如Pageable对象
//根据作者和书名的关键字分页查询
Page<BookInfo> getAllByBookNameContainsOrBookAuthorContains(String nameKeyword,String authorKeyword,Pageable pageable);
Page<BookInfo> pageInfo = bookInfoDao.getAllByBookNameContainsOrBookAuthorContains("龙","山",PageRequest.of(0,5));
//分页相关数据保存在pageInfo对象中
聚合函数分组查询
自定义SQL
在数据访问层接口中的方法上,可以加入@Query注解,默认要使用HQL(Hibernate专用)格式的语句。
如果要使用原生的SQL语句,需要添加nativeQuery=true属性,用value属性定义SQL语句
/** 在JPA中,如果要使用自定义的SQL语句* nativeQuery = true 开启原生SQL语句* value="sql语句"* */
@Query(nativeQuery = true, value = "select book_author,count(book_id) from book_info group by book_author")
List testQuery();
@Test
void test(){List list = bookInfoDao.testQuery();//查询的结果为集合,集合中保存的是每一行数据for (Object row : list) {//每一行页数一个对象数组Object[] obj= (Object[])row;//根据索引得到查询出的内容System.out.println(obj[0]+"---"+obj[1]);}
}
自定义SQL中带参数
SQL语句中的":XXX"表示参数
如果方法的形参名和xxx一致时直接使用,如果不一致,在形参上加入@Param注解设置形参名
/** 根据作者查询其图书总库存* 使用":形参名"在SQL语句中带参数* 在方法中通过@Prama定义形参* */
@Query(nativeQuery = true, value = " select book_author,sum(book_num) from book_info where book_author=:zuozhe")
List testQuery3(@Param("zuozhe") String xxx);
@Test
void test(){List list = bookInfoDao.testQuery3("金庸");//查询的结果为集合,集合中保存的是每一行数据for (Object row : list) {//每一行页数一个对象数组Object[] obj= (Object[])row;//根据索引得到查询出的内容System.out.println(obj[0]+"---"+obj[1]);}
}
关联查询
主表book_type
从表book_info
实体类
主表实体BookType
@Entity
@Data
public class BookType {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Integer typeId;private String typeName;
}
从表实体BookInfo
- 无需写出外键字段属性
- 额外添加外键字段对应的实体类对象属性
@Data
@Entity
public class BookInfo {@Id//主键字段//主键生成策略,GenerationType.IDENTITY表示MySQL自增@GeneratedValue(strategy = GenerationType.IDENTITY)private Integer bookId;//private Integer typeId;private String bookName;private String bookAuthor;//如果字段名和属性名不一致,使用@Column指定字段名@Column(name = "book_price")private Integer price;private Integer bookNum;private String publisherDate;//多对一查询,以当前从表信息为主体,关联相应的主表信息@JoinColumn(name = "type_id")//使用type_id字段进行多对一查询@ManyToOne//多对一private BookType bt;
}
使用
多对一查询,调用dao中的查询方法,就会自动给外键字段对应的对象赋值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SJ99D0dD-1676799934893)(day16day17-SpringBoot+JPA.assets/image-20230214111732161.png)]
添加时,参数所需外键字段,使用外键字段对应的对象名代替
//添加 @PostMapping("/book") public RestResult<BookInfo> insert(BookInfo bookInfo) {return RestResult.ok("添加成功", bookInfoDao.save(bookInfo)); }
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U4mm8cTB-1676799934893)(day16day17-SpringBoot+JPA.assets/image-20230214113125279.png)]
如果根据外键字段查询,要在从表dao中定义方法findBy外键对象名_外键对象属性名(数据类型 外键字段)
//如果根据外键字段查询,方法名写为 By外键实体类属性名_属性名 List<BookInfo> getAllByBt_TypeId(Integer typeId);
前后端分离项目
前后端分离,就是将web应用中的前端页面和后端代码分开完成、部署。
- 前后端的开发者只需要完成各自的事情,最终以文档的形式约定数据接口(URL、参数、返回值、请求方式)
- 前后端分别用独立的服务器
- 后端只需处理数据并提供访问接口(路径),以RESTFul风格的JSON格式传输数据
- 前端只需负责渲染页面和展示数据
传统项目和前后端分离项目对比
传统项目
前端和后端的代码运行在一个服务器上,页面经由控制器跳转
SSM项目、图书管理系统、答题系统
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MJnehntM-1676799934893)(day16-SpringBoot+JPA.assets/image-20230213170658853.png)]
前后端分离项目
前后端的代码分别运行在各自的服务器上
后端提供JSON格式字符串的数据接口
前端负责跳转、解析JSON数据。
酒店客房管理系统
前后端分离项目后端控制层设计
请求方式设计:RESTFul风格
风格,不是标准,可以不用强制遵循。
RESTFul风格:用不同的请求方式去访问同一个URL地址时,执行不同的操作。
特点
- 通过URL就能知道当前在哪个模块
- 通过不同的请求方式决定执行什么操作
- 通过返回的状态码得到操作结果
使用RESTFul风格和普通方式对比
普通方式
localhost:8080/user/queryAll 查询所有
localhost:8080/user/queryById?id=1001 条件查询
localhost:8080/user/insert?name=ez&sex=男&age=20 添加
localhost:8080/user/update?name=ez&id=1001 修改
localhost:8080/user/delete?id=1001 删除
RESTFul风格
localhost:8080/user 查询所有get请求
localhost:8080/user/1001 条件查询get请求
localhost:8080/user 添加post请求
localhost:8080/user 修改put请求
localhost:8080/user/1001 删除delete请求
RESTFul风格具体使用
在请求映射的命名上,统一用小写字母的名词形式表示当前位于哪个模块。如/user、/book_info
访问时如果要传参,使用"/模块名/参数"方式,配合controller中的@PathVariable获取
@GetMapping("/book/{id}") public BookInfo queryById(@PathVariable("id")Integer id){return service.findById(id); }
在controller的方法上,使用@XXXMapping()设置访问该方法的请求方式
- @GetMapping(“路径”) 查询
- @PostMapping(“路径”) 添加
- **@PutMapping(“路径”) ** 修改
- **@DeleteMapping(“路径”) ** 删除
- @RequestMapping(value=“路径”,method=RequestMethod.GET/POST/PUT/DELETE))
如果请求方式不匹配,会报405异常
在同一个controller中,不能出现两个请求方式和路径都一致的方法
返回值设计
前后端分离项目的控制层方法的返回值也需要进行统一。
返回值通常包含以下信息
- 传递状态,用状态码表示Integer code
- 传递消息,用字符串表示String msg
- 传递集合,用集合表示List list
- 传递对象,用对象表示Object obj
将这些信息封装到一个对象中,这个对象称为返回结果类RestResult对象
Java技术栈
服务器端
JavaSE(API、OOP)、JavaEE(Servlet、Spring、SpringMVC)
tomcat
前端0
HTML+CSS+JS+JQUERY、Bootstrap、LayUI、EasyUI、VUE
数据库
MySQL、Oracle、Redis
JDBC、SpringJDBC、MyBatis、MyBatisPlus、JPA
工具
IDEA、HBuilder、VSCode、Notepad++、Sublime、Navicat、Postman
JavaEE过程
Servlet + JDBC + JSP(bootstrap) 图书商场
Spring + SpringMVC + SpringJDBC + JSP(bootstrap)
Spring + SpringMVC + MyBatis+ JSP 图书管理系统SSM
SpringBoot + MyBatis + html(LayUI) 酒店客房管理(可前后端分离)
SpringBoot + MyBatisPlus + html(Thymeleaf+bootstrap) 答题系统
SpringBoot + Spring Data JPA
华清远见-重庆中心-框架阶段技术总结相关推荐
- 华清远见-重庆中心-框架阶段技术总结/知识点梳理
文章目录 华清远见-重庆中心-框架阶段技术总结/知识点梳理/个人总结 框架 Java主流框架 Spring 概念 组成 名词解释 IOC DI Spring控制台应用 1.创建一个普通的Maven项目 ...
- 华清远见-重庆中心-前端阶段技术总结
华清远见-重庆中心-前端阶段技术总结 HTML Hyper Text Markup Language 超文本标记语言 超文本:超级文本/超链接文本,超越了文本的限制,如多媒体文件.超链接等. 标记:也 ...
- 华清远见-重庆中心-前端阶段技术总结/个人总结
目录 认识前端 客户端/服务器 模式 使用方法 特点 浏览器/服务器 模式 使用方法 特点 学习前端的重要性 浏览器 作用 主流/推荐的浏览器 前端学习网站 推荐编写软件 HTML部分 定义 标签 标 ...
- 华清远见-重庆中心-JavaWeb阶段技术总结/知识点梳理/个人总结
文章目录 JavaWeb B/S与C/S模式 网站 网页 网络服务器 Tomcat 下载 目录结构 Maven 使用IDEA创建基于Maven的Web项目 1.新建webapp模板 2.设置项目名称和 ...
- 华清远见-重庆中心-数据库阶段技术总结/知识点梳理/个人总结/面试题解析
目录 Java Web阶段核心内容 (一)初识Web 1.JavaWeb定义 2.B/S与C/S模式 3.网站与网页 4.Tomcat服务器 5.Maven 6.常见的Http状态码 7.Servle ...
- 华清远见-重庆中心-数据库阶段技术总结/知识点梳理/个人总结/关于JavaWeb技术的解析(看法)
JavaWeb 使用Java开发Web服务的技术,统称为JavaWeb. B/S与C/S模式 B/S:Browser/Server 浏览器/服务器模式 用户只需要一个浏览器即可访问服务器 C/S:Cl ...
- 华清远见-重庆中心-数据库阶段技术总结:
绝对路径 <a href="localhost:8080/system/pages/hello.html">跳转</a> 相对路径问题 / 表示从根目录(域 ...
- 华清远见-重庆中心-框架部分技术总结
目录 框架 Java主流框架 Spring 概念 组成 名词解释 IOC DI AOP Spring控制台应用 1.创建一个普通的Maven项目,不选择模板 2.添加Spring核心依赖 3.创建一个 ...
- 华清远见重庆中心—JS阶段技术总结/个人总结
目录 简单的案例 1.制作简易的课程表 2.制作一个几乎包揽html全部所学知识的简易网页 3.简易的登录界面 Js企业面试题 1.javascript基本数据类型? 2.浅谈javascript中变 ...
最新文章
- 【Qt】Ubuntu18.04下解决Qt出现qt.qpa.plugin:Could not load the Qt platform plugin “xcb“问题
- vue当前浏览器是否为ie_Vue进阶(六十八):JS-判断当前浏览器是否为IE
- 20年研发管理经验谈(五)
- Careercup - Google面试题 - 5424071030341632
- Taro+react开发(12)--注意引入user
- LayoutInflater.inflate()方法两个参数和三个参数
- truncate table语句和delete table语句的区别
- 浅析如何通过PHP类的反射来实现依赖注入
- 编译速度谁“最快”?25岁的 C++Builder 还能打!
- 三合一乐高迷你机器人_乐高太贵?这10个品牌积木玩具购买指南请收好
- 教你几招Mac的省电小技巧
- 安装使用FLTK图形库
- 工业互联网标识解析体系
- iOS 图片裁剪功能。
- 欧拉降幂公式模板hdu4704
- Linux notifier chain
- 杭电校赛(油菜花王国)
- C语言修饰词之violate使用
- BugMeNot:查找和共享登录名(一个神奇的网站)
- 轻售后、缺服务,产销双增背景下家电行业“后院失火”?