框架

一套规范。

实际是他人实现的一系列接口和类的集合。通入导入对应框架的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

华清远见-重庆中心-框架阶段技术总结相关推荐

  1. 华清远见-重庆中心-框架阶段技术总结/知识点梳理

    文章目录 华清远见-重庆中心-框架阶段技术总结/知识点梳理/个人总结 框架 Java主流框架 Spring 概念 组成 名词解释 IOC DI Spring控制台应用 1.创建一个普通的Maven项目 ...

  2. 华清远见-重庆中心-前端阶段技术总结

    华清远见-重庆中心-前端阶段技术总结 HTML Hyper Text Markup Language 超文本标记语言 超文本:超级文本/超链接文本,超越了文本的限制,如多媒体文件.超链接等. 标记:也 ...

  3. 华清远见-重庆中心-前端阶段技术总结/个人总结

    目录 认识前端 客户端/服务器 模式 使用方法 特点 浏览器/服务器 模式 使用方法 特点 学习前端的重要性 浏览器 作用 主流/推荐的浏览器 前端学习网站 推荐编写软件 HTML部分 定义 标签 标 ...

  4. 华清远见-重庆中心-JavaWeb阶段技术总结/知识点梳理/个人总结

    文章目录 JavaWeb B/S与C/S模式 网站 网页 网络服务器 Tomcat 下载 目录结构 Maven 使用IDEA创建基于Maven的Web项目 1.新建webapp模板 2.设置项目名称和 ...

  5. 华清远见-重庆中心-数据库阶段技术总结/知识点梳理/个人总结/面试题解析

    目录 Java Web阶段核心内容 (一)初识Web 1.JavaWeb定义 2.B/S与C/S模式 3.网站与网页 4.Tomcat服务器 5.Maven 6.常见的Http状态码 7.Servle ...

  6. 华清远见-重庆中心-数据库阶段技术总结/知识点梳理/个人总结/关于JavaWeb技术的解析(看法)

    JavaWeb 使用Java开发Web服务的技术,统称为JavaWeb. B/S与C/S模式 B/S:Browser/Server 浏览器/服务器模式 用户只需要一个浏览器即可访问服务器 C/S:Cl ...

  7. 华清远见-重庆中心-数据库阶段技术总结:

    绝对路径 <a href="localhost:8080/system/pages/hello.html">跳转</a> 相对路径问题 / 表示从根目录(域 ...

  8. 华清远见-重庆中心-框架部分技术总结

    目录 框架 Java主流框架 Spring 概念 组成 名词解释 IOC DI AOP Spring控制台应用 1.创建一个普通的Maven项目,不选择模板 2.添加Spring核心依赖 3.创建一个 ...

  9. 华清远见重庆中心—JS阶段技术总结/个人总结

    目录 简单的案例 1.制作简易的课程表 2.制作一个几乎包揽html全部所学知识的简易网页 3.简易的登录界面 Js企业面试题 1.javascript基本数据类型? 2.浅谈javascript中变 ...

最新文章

  1. 【Qt】Ubuntu18.04下解决Qt出现qt.qpa.plugin:Could not load the Qt platform plugin “xcb“问题
  2. vue当前浏览器是否为ie_Vue进阶(六十八):JS-判断当前浏览器是否为IE
  3. 20年研发管理经验谈(五)
  4. Careercup - Google面试题 - 5424071030341632
  5. Taro+react开发(12)--注意引入user
  6. LayoutInflater.inflate()方法两个参数和三个参数
  7. truncate table语句和delete table语句的区别
  8. 浅析如何通过PHP类的反射来实现依赖注入
  9. 编译速度谁“最快”?25岁的 C++Builder 还能打!
  10. 三合一乐高迷你机器人_乐高太贵?这10个品牌积木玩具购买指南请收好
  11. 教你几招Mac的省电小技巧
  12. 安装使用FLTK图形库
  13. 工业互联网标识解析体系
  14. iOS 图片裁剪功能。
  15. 欧拉降幂公式模板hdu4704
  16. Linux notifier chain
  17. 杭电校赛(油菜花王国)
  18. C语言修饰词之violate使用
  19. BugMeNot:查找和共享登录名(一个神奇的网站)
  20. 轻售后、缺服务,产销双增背景下家电行业“后院失火”?

热门文章

  1. 对治疗肠胃炎简单有效的按摩法 - 生活至上,美容至尚!
  2. 软件定义汽车下,大众“笨重”转型
  3. 右键菜单变宽了的原因及解决办法
  4. android锁屏软件屏蔽状态栏下拉
  5. 白光干涉测量的简单理解(附matlab仿真代码)
  6. 快递查询API,我推荐“爱快递”
  7. 关于所谓的“大学好坏不重要,只要自己努力就行”
  8. 跟我学习Spring Security--在线宠物商店开发(二)
  9. 安装win10后,光驱显示电源关闭的问题
  10. 关于原生html和js上传文件的处理