框架是一套规范。

实际是他人实现的一系列接口和类的集合。通过导入对应框架的jar文件(Maven项目导入对应的依赖),进行适当的配置,就能使用其中的所有内容。开发者可以省去很多模板代码

Spring

是一个轻量级开源的Java框架,是一个管理项目中对象的容器,也是其他框架的粘合器,目的就是对项目进行解耦

核心:IOC控制反转和AOP面向切面编程

控制反转是一种思想,就是让创建对象的控制权由自身交给第三方,控制翻转这种思想,通过依赖注入的方式实现

bean标签常用属性

属性

作用

class

定义类的全限定名

id

定义对象的名称

lazy-init

设置是否为懒加载,默认值为false,在解析配置文件时就会创建对象。设置为true表示懒加载,只有在getBean()时才会创建对象。

scope

单例/原型模式。默认值为singleton,表示单例模式,只会创建一个对象。设置为prototype,表示原型模式,每次调用getBean()就会创建一个对象

init-method

初始化方法,在创建完该对象时自动调用的方法,该方法只能是无参方法,该属性的值只需要写方法名即可

destory-method

销毁时触发的方法。Spring容器关闭时自动调用的方法,该方法只能是无参方法,只有在单例模式下有效

属性注入

给某个bean标签添加属性的两种方式:setter注入和构造器注入

setter注入

该方法注入属性时,类中必须要有set方法

该标签的name属性通常表示该对象的某个属性名,但实际是setXXX()方法中的XXX单词。

该标签的value属性表示给该类中的某个属性赋值,该属性的类型为原始类型或String。

<!--注入Car类对象,并用set方式注入其属性-->
<bean class="com.hqyj.SetterInject.Car" id="c"><!--该属性是字符串类型或原始类型,使用value--><property name="brand" value="宝马"></property><property name="color" value="白色"></property>
</bean>

构造器注入

这种方式注入属性时,类中必须有相应的构造方法(有参)

该标签的name属性表示构造方法的参数名,index属性表示构造方法的参数索引。

赋值时,原始类型和字符串用value,引用类型用ref。

<!--注入Person类对象 并用构造方法注入其属性-->
<bean class="com.hqyj.SetterInject.Person" id="p2"><!--constructor-arg表示构造方法参数name是参数名 index是参数索引--><constructor-arg name="name" value="张三"></constructor-arg><constructor-arg index="1" value="23"></constructor-arg><!--c是Car类的对象--><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;//电影类型private String showTime;//放映时间:最终格式为yyyy/MM/dd HH:mm:ss//忽略了setter/getter/gouzao方法等
}

List类型属性注入

<!--注入movie对象-->
<bean class="com.hqyj.SetterInject.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="2020/06/10 0:0:0"></property>
</bean>

Set类型属性注入

//宠物类
public class Pet {private String petType;private String petNickName;private int petAge;public Pet(String petType, String petNickName, int petAge) {this.petType = petType;this.petNickName = petNickName;this.petAge = petAge;}//省略了setter/getter/toString方法public Pet() {}
}//宠物店类
public class PetShop {private String shopName;private Set<Pet> petList;public PetShop(String shopName, Set<Pet> petList) {this.shopName = shopName;this.petList = petList;}//省略了setter/getter/toString方法public PetShop() {}
}

注入:

<bean class="com.hqyj.SetInject.Pet" id="pet1"><property name="petType" value="二哈"></property><property name="petNickName" value="乐乐"></property><property name="petAge" value="3"></property>
</bean>
<bean class="com.hqyj.SetInject.Pet" id="pet2"><property name="petType" value="金毛"></property><property name="petNickName" value="linck"></property><property name="petAge" value="2"></property>
</bean><bean class="com.hqyj.SetInject.PetShop" id="petShop"><property name="shopName" value="狗狗乐园"></property><property name="petList"><set><ref bean="pet1"></ref><ref bean="pet2"></ref></set></property>
</bean>

Map属性注入

<!--实体类-->
public class Cinema {private String name;<!--定义Map保存上映时间表,键是影厅号,值是电影对象-->private Map<Integer,Movie> timeTable;public Cinema(String name, Map<Integer, Movie> timeTable) {this.name = name;this.timeTable = timeTable;}public Cinema() {}<!--省略了toString()、getter()、getter()方法-->
}
<!--注入Cinema对象-->
<bean class="com.hqyj.SetterInject.Cinema" id="cinema"><property name="name" value="万达影城"></property><property name="timeTable"><!--Map类型属性赋值,标明键和值的类型--><map key-type="java.lang.Integer" value-type="com.hqyj.SetterInject.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>

现在时间注入

<!--注入SimpleDateFormat对象,设置日期格式-->
<bean class="java.text.SimpleDateFormat" id="sdf"><!--如果构造方法注入时,该构造方法只有一个参数,可以不用name或index--><constructor-arg index="0" value="yyyy/MM/dd"></constructor-arg>
</bean>
<!--注入Date对象--> .
<bean class="java.util.Date" id="now"></bean><bean class="com.hqyj.SetterInject.Movie" id="movie1"><property name="类中的时间属性名"><bean factory-bean="sdf" factory-method="format"><constructor-arg ref="now"></constructor-arg></bean></property>
</bean>

属性自动注入autowire

实现自动注入

在某个bean标签中,加入autowire属性,设置值为"byName"或"byType",通常设置为"byType"

public class Car {private String brand;private String color;public Car(String brand, String color) {this.brand = brand;this.color = color;}public Car() {}//省略了setter/getter/toString方法
}//Person类
public class Person {private String name;private int age;private Car car;public Person(String name, int age,Car car) {this.name = name;this.age = age;this.car = car;}public Person() {}//省略了setter/getter/toString方法
}

配置文件:

<!--在容器中注入Car类型的bean-->
<bean class="com.hqyj.SetterInject.Car" id="car"><property name="brand" value="宝马"></property><property name="color" value="白色"></property>
</bean><!--注入Person类的bean-->
<!--autowire="byType "表示自动检测该类中是否需要使用引用类型参数,如果容器中正好有唯一的一个对应类型的bean, 就会自动赋值给对应的属性-->
<bean class="com.hqyj.AutoWire.Person" id="person" autowire="byType"><property name="name" value="王海"></property><property name="age" value="45"></property>
</bean><!--autowire="byName"表示自动检测该类中的setxxx方法,如果某个setxxx方法的x和容器某个对象的id对应,就会自动赋值给对应的属性-->
<bean class="com.hqyj.AutoWire.Person" id="person2" autowire="byName"><property name="name" value="王海"></property><property name="age" value="45"></property>
</bean>

主方法:

public static void main(String[] args) {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");Person person = context.getBean("person", Person.class);System.out.println(person);context.close();
}

autowire属性的值

byType

  • 类中要有被注入的属性的setter()方法

  • 被自动注入的对象可以没有id

  • Spring容器中,某个对象的类型要与该setter()方法的参数类型-致,且容器中只有一个该类型的对象

  • 如setCar(Car C), Spring就会自动在容器中寻找类型为Car的对象自动装配

byName

  • 类中要有被注入的属性的setter()方法

  • 被自动注入的对象必须要有id

  • 实际是根据setXXX()方法set后的单词XXX关联

  • 如setCar(Car c),Spring就会自动在容器中寻找id为car的对象自动装配

Spring核心注解

在spring配置文件中进行配置:

 <!--如果要使用Spring注解,需要加入这段话,表示扫描指定包下所有使用了注解的类-->
<context:component-scan base-package="com.hqyj.Seconds.bookSystem"></context:component-scan>

BookDao类:

//这个注解相当于在配置文件中加入<bean class= "com.hqyj.Seconds.bookSystem.dao.BookDao"></bean>
@Component
publicclassBookDao {publicvoidqueryAll(){System.out.println("模拟查询所有图书信息");}
}

BookService类

@Component//这个注解相当于在配置文件中加入<bean class= "com.hqyj.Seconds.bookSystem.service.BookServicel"></bean>
publicclassBookService {@Autowired//这个注解相当于<bean class= "com.hqyj.Seconds.bookSystem.service.BookServicel"></bean>中加入autowire=byTypeprivateBookDaobookDao;
​publicvoidshowAll(){System.out.println("经过service执行dao中的方法");bookDao.queryAll();}
}

BookController类

//如果没有设置名称,获取当前类的对象,名称为类名的驼峰俞名法形式。如BookController, 获取时使用bookController获取
@Component
//这里的value表示给该bean设置id名,调用时使用controller
//@Component(value = "controller")
publicclassBookController {@AutowiredprivateBookServicebookService;publicvoidshowAll(){System.out.println("经过controller,调用service中的方法");bookService.showAll();}
}

Main方法

publicclassBookMain {publicstaticvoidmain(String[] args) {ClassPathXmlApplicationContextcontext=newClassPathXmlApplicationContext("book_system.xml");//BookController类中使用@Component注解时使用BookControllerbean=context.getBean("bookController",BookController.class);//BookController类中使用@Component(value="controller")或者@Controller(value = "controller")注解时使用//BookController bean = context.getBean("controller",BookController.class);bean.showAll();}
}

类上加的注解

  • @Component

  • 当一个类不好归纳时,使用该注解定义为普通组件

  • @Controller

  • 定义一个类为控制层组件

  • @Service

  • 定义一个类为业务逻辑层组件

  • @Repository

  • 定义一个类为持久层(数据访问层/dao层)组件

  • @Lazy/@Lazy(value=true)

  • 设置该类为懒加载

  • @Scope/@Scope(valuye="singleton/prototype")

  • 设置为单例/原型模式,默认单例模式

说明

以上注解的公共特点

  • 都是将对应类的对象注入到Spring容器中,用于替换配置文件中的bean标签

  • 默认是单例模式,只会创建一个对象,非懒加载,容器加载时会自动创建。

  • 默认注入的对象id为当前类的类名首字母小写形式

  • 如在BookDao类上添加@Component,id默认为bookDao

  • 可以通过注解的value属性自定义注入的对象的id名,如@Component(value="key")表示注入的对象id为key

属性上加的注解

  • @Autowired

  • 优先使用byType方式从Spring容器中获取对应类型的对象自动装配,先检索Spring容器中对应类型的数量。如果数量为0,直接报错;如果数量为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包,需要引入对应依赖

<!--pom.xml-->
<dependency><groupId>javax.annotation</groupId><artifactId>javax.annotation-api</artifactId><version>1.3.2</version>
</ dependency>

web项目中使用Spring

添加依赖

<!--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集成-->
<dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.3.23</version>
</dependency>

在main目录下创建java和resources目录,修改web.xml版本为4.0


在resources目录下创建spring配置文件application.xml,扫描使用了注解的根包

<context:component-scan base-package="com.hqyj.springweb"></context:component-scan>

创建一个类,使用@Componet注解将其注入到Spring容器中

@Component
public class Pojo {public void fun(){System.out.println("hello springweb");}
}

配置监听器用于初始化Spring容器

<!--配置全局监听器用于初始化Spring容器-->
<listener><!--ContextLoaderListener是一个全局监听器--><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--定义全局参数-->
<context-param><!--该监听器需要设置要读取的Spring配置文件路径--><param-name>contextConfigLocation</param-name><!--只是Spring配置文件的路径c1asspath:表示从根目录出发--><param-value>classpath:application.xml</param-value>
</context-param>

创建一个servlet,范围跟该servlet,获取spring容器,从容器中获取

@org.springframework.stereotype.Controller
@WebServlet("/hello")
public class MyController extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//获取Spring容器WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());//从容器中获取某个beanPojo pojo = context.getBean("pojo", Pojo.class);pojo.fun();}
}

如何初始化spring容器

实际就是如何在web应用中解析Spring的配置文件

在控制台应用程序中,可以在main方法中通过ClassPathXmlApplicationContext来解析application.xml文件, 初始化Spring容器。

在web项目中没有main方法,只有servlet中的service,如果在service方法中创建ClassPathXmlApplicationContext对象,会每次访问都执行

而Spring容器只需初始化一次,在项目启动时就解析application.xml文件,全局监听器就是一个很好的选择。

spring-web包中提供了一个ContextLoaderListener类, 它实现了ServletContextListener,属于项目级别的全局监听器。

这个类需要一个contextConfigLocation参数,表示要解析的application.xml文件的路径。

这个监听器会在项目启动时,读取指定的Spring配置文件路径,并且创建WebApplicationContext对象,即Spring容器, 这个对象保存在ServletContext中

在spring-web项目中使用Spring-jdbc

1.添加依赖

<dependencies><!--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集成--><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.3.23</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.31</version></dependency><!--jstl--><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><!--spring-jdbc--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.23</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency>
</dependencies>

2.创建包结构(controller、servlet、dao、entity),创建实体类

publicclassHero {privateintid;privateStringname;privateStringposition;privateStringsex;private  intprice;privateStringshelfDate;
​publicHero(intid, Stringname, Stringposition, Stringsex, intprice, StringshelfDate) {this.id=id;this.name=name;this.position=position;this.sex=sex;this.price=price;this.shelfDate=shelfDate;}
​publicHero(Stringname, Stringposition, Stringsex, intprice, StringshelfDate) {this.name=name;this.position=position;this.sex=sex;this.price=price;this.shelfDate=shelfDate;}publicHero() {}//忽略setter/getter/toString方法
}

3.在spring配置文件中配置数据源和JDBC模板

<?xmlversion="1.0" encoding="UTF-8"?>
<beansxmlns="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-scanbase-package="com.hqyj.springweb"></context:component-scan>
​<!--配置数据库--><beanclass="org.springframework.jdbc.datasource.DriverManagerDataSource"id="dataSource"><!--配置连接驱动--><propertyname="driverClassName"value="com.mysql.cj.jdbc.Driver"></property><!--配置mysql地址--><propertyname="url"value="jdbc:mysql://localhost:3306/gamedb?serverTimezone=Asia/Shanghai"></property><propertyname="username"value="root"></property><propertyname="password"value="123456"></property></bean>
​<!--配置JDBC模板--><beanclass="org.springframework.jdbc.core.JdbcTemplate"id="jdbcTemplate"><!--设置要操作的数据源--><propertyname="dataSource"ref="dataSource"></property></bean>
</beans>

4.数据访问层(dao)的写法

@Repository
publicclassHeroDao {@Autowired//通过jdbc模板对象实现CRUDprivateJdbcTemplatejdbcTemplate;
​publicList<Hero>queryAll() {Stringsql="select * from hero";//BeanPropertyRowMapper对象表示将查询到的字段与指定的类中的属性进行映射BeanPropertyRowMapper<Hero>mapper=newBeanPropertyRowMapper<>(Hero.class);//query()方法执行查询List<Hero>list=jdbcTemplate.query(sql, mapper);returnlist;}
​publicbooleandelete(intid) {Stringsql="delete from hero where id=?";inti=jdbcTemplate.update(sql, id);returni>0;}
​publicbooleaninsert(Herohero){Stringsql="insert into hero values(null,?,?,?,?,?)";intinsert=jdbcTemplate.update(sql, hero.getName(), hero.getPosition(), hero.getSex(), hero.getPrice(), hero.getShelfDate());returninsert>0;}
​publicHerofindById(intid){Stringsql="select * from hero where id=?";BeanPropertyRowMapper<Hero>mapper=newBeanPropertyRowMapper<>(Hero.class);Herohero=jdbcTemplate.queryForObject(sql, mapper, id);returnhero;}
​publicbooleanupdate(Herohero){Stringsql="update hero set name=?,position=?,sex=?,price=?,shelf_date=? where id=?";intupdate=jdbcTemplate.update(sql, hero.getName(), hero.getPosition(), hero.getSex(), hero.getPrice(), hero.getShelfDate(), hero.getId());returnupdate>0;}
}​

5.控制层(controller)写法

@WebServlet("/hero")
publicclassHeroServletextendsHttpServlet {@Overrideprotectedvoidservice(HttpServletRequestreq, HttpServletResponseresp) throwsServletException, IOException {req.setCharacterEncoding("utf-8");resp.setContentType("text/html;charset=utf-8");//获取Spring容器,获取HeroDao对象WebApplicationContextcontext=WebApplicationContextUtils.getWebApplicationContext(getServletContext());HeroDaoheroDao=context.getBean("heroDao", HeroDao.class);
​Stringop=req.getParameter("op");switch (op) {case"queryAll":List<Hero>heroes=heroDao.queryAll();req.setAttribute("list", heroes);req.getRequestDispatcher("./pages/select.jsp").forward(req, resp);System.out.println(heroes);break;case"delete":Stringid=req.getParameter("id");heroDao.delete(Integer.parseInt(id));resp.sendRedirect("./hero?op=queryAll");break;case"insert":Stringname=req.getParameter("name");Stringposition=req.getParameter("position");Stringsex=req.getParameter("sex");intprice=Integer.parseInt(req.getParameter("price"));Stringdate=req.getParameter("date");Herohero=newHero(name, position, sex, price, date);heroDao.insert(hero);resp.sendRedirect("./hero?op=queryAll");break;case"findById":intbyId=Integer.parseInt(req.getParameter("id"));HerobyId1=heroDao.findById(byId);req.setAttribute("hero",byId1);req.getRequestDispatcher("./pages/update.jsp").forward(req, resp);break;case"update":intupdateId=Integer.parseInt(req.getParameter("id"));Stringname1=req.getParameter("name");Stringposition1=req.getParameter("position");Stringsex1=req.getParameter("sex");intprice1=Integer.parseInt(req.getParameter("price"));Stringdate1=req.getParameter("date");Herohero1=newHero(updateId, name1, position1, sex1, price1, date1);heroDao.update(hero1);resp.sendRedirect("./hero?op=queryAll");break;}}
}

6.JSP页面

<%@taglibprefix="c"uri="http://java.sun.com/jsp/jstl/core" %>
<%@pagecontentType="text/html;charset=UTF-8"language="java" %>
<html>
<head><title>查询所有</title><style>table {border-collapse: collapse;margin: 50pxauto;}
​td,th {width: 100px;height: 20px;border: 1pxsolidblack;}td{text-align: center;}</style>
</head>
<body>
<formaction="${pageContext.request.contextPath}/hero"method="post"><inputtype="hidden"value="query"name="op"><table><tr><th>编号</th><th>英雄名称</th><th>英雄位置</th><th>英雄性别</th><th>英雄价格</th><th>上架日期</th><thcolspan="2">操作</th></tr><c:forEachitems="${list}"var="hero"><tr><td>${hero.id}</td><td>${hero.name}</td><td>${hero.position}</td><td>${hero.sex}</td><td>${hero.price}</td><td>${hero.shelfDate}</td><td><ahref="${pageContext.request.contextPath}/hero?op=delete&id=${hero.id}">删除</a></td><td><ahref="${pageContext.request.contextPath}/hero?op=findById&id=${hero.id}">修改</a></td></tr></c:forEach><tr><tdcolspan="8"><ahref="${pageContext.request.contextPath}/pages/insert.jsp">添加</a></td></tr></table>
</form>
</body>
</html>
​
<!--新增界面insert.jsp-->
<formaction="${pageContext.request.contextPath}/hero"method="post"><inputtype="hidden"value="insert"name="op"><table><tr><td>英雄角色</td><td><inputtype="text"name="name"></td></tr><tr><td>英雄位置</td><td><inputtype="text"name="position"></td></tr><tr><td>英雄性别</td><td><inputtype="text"name="sex"></td></tr><tr><td>英雄价格</td><td><inputtype="number"name="price"></td></tr><tr><td>上架日期</td><td><inputtype="date"name="date"></td></tr><tr><td><inputtype="submit"value="添加"></td></tr></table>
</form>
<!--修改界面update.jsp-->
<formaction="${pageContext.request.contextPath}/hero"method="post"><inputtype="hidden"value="update"name="op"><inputtype="hidden"name="id"value="${hero.id}"><table><tr><td>英雄角色</td><td><inputtype="text"name="name"value="${hero.name}"></td></tr><tr><td>英雄位置</td><td><inputtype="text"name="position"value="${hero.position}"></td></tr><tr><td>英雄性别</td><td><inputtype="text"name="sex"value="${hero.sex}"></td></tr><tr><td>英雄价格</td><td><inputtype="number"name="price"value="${hero.price}"></td></tr><tr><td>上架日期</td><td><inputtype="date"name="date"value="${hero.shelfDate}"></td></tr><tr><td><inputtype="submit"value="修改"></td></tr></table>
</form>

JDBCTemplate常用方法

方法

作用

说明

query(String sgl, RowMapper mapper)

无条件查询

返回值为List集合

update(String sql)

无条件更新(删除、修改)

返回值是受影响的行数

query(String sgl, RowMapper mapper,Object... objs)

条件查询

可变参数为?的值

update(String sql,Object...objs)

条件更新(添加,删除,修改)

可变参数为?的值

gueryForObject(String sgl, RowMapper mapper)

无条件查询单个对象

返回值是指定对象

gueryForObject(String sgl, RowMapper mapper,Object...objs)

条件查询单个对象

返回值是指定对象

execute(String sql)

执行指定的sql

无返回值

SpringMVC

在web阶段中,控制层是由servlet实现,传统的Servlet,需要创建、重写方法、配置映射。使用时极不方便,SpringMVC可以替换Servlet。

SpringMVC是Spring框架中位于Web开发中的一个模块, 是Spring基于MVC设计模式设计的轻量级Web框架。

使用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

<?xmlversion="1.0" encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:mvc="http://www.springframework.org/schema/mvc"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/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!--设置扫描使用了注解的根包--><context:component-scanbase-package="com.hqyj.springmvc"></context:component-scan>
</beans>
  • 在web.xml中使用监听器初始化

<?xmlversion="1.0" encoding="UTF-8"?>
<web-appxmlns="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.xm

  • 配置要扫描的控制层类所在的包名

  • 配置内部资源视图解析器以及视图路径的前后缀

<?xmlversion="1.0" encoding="UTF-8"?>
<beansxmlns="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-scanbase-package="com.hqyj.springmvc.controller"></context:component-scan><!--配置内部资源视图解析器--><beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"><!--最终控制层跳转的页面所在的路径及页面自身后缀名--><!--jsp页面不建议直接通过浏览器访问。在EWEB-INF目录下的资源,无法通过浏览器直接访问,所以将jsp保存在WEB-INF目录下,最好创建一个pages--><propertyname="prefix"value="/WEB-INF/pages/"></property><!--现阶段使用jsp输出数据,所以后缀名为.jsp--><propertyname="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的初始化参数,用于读取SrpingMVC配置文件--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param>
</servlet>
<servlet-mapping><servlet-name>dispatcherServlet</servlet-name><!--设置该serlvet的映射为/或*.do--><url-pattern>/</url-pattern>
</servlet-mapping>

5.在WEB-INF目录下创建一个pages目录,在其中创建一个welcome.jsp页面

  • 通常jsp页面不允许被浏览器直接访问,需要保存在WEB-INF目录下

6.编写控制层代码

  • 在controller包下创建一个类,加上@controller注解

  • 方法加入@RequestMapping()注解表示访问该方法的映射

  • 该类中定义有的方法返回值通常为字符串,表示某个页面的名称,也可以是另一个controller中的方法映射名

//加入@Controller注解表示该类是一个控制层类,替换之前的servlet
@Controller
//该注解如果只设置请求映射,直接填字符申
@RequestMapping(path="/first")
publicclassHelloController {//该注解如果还有其他参数要设置,路径用path赋值@RequestMapping(path="/hello")publicStringhello(){//返回的字符申是某个页面的名称或另一个控制层中方法的请求映射return"welcome";//welcome是jsp页面名}
}

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}")
publicStringfun(@PathVariable("path") StringpageName){}

//当前方法如果通过localhost:8080/项目名/he11o访问,就会跳转到hello.jsp

//当前方法如果通过localhost: 8080/项目名/error访问,就会跳转到error .jsp

//映射中的/{path}就是获取路径中的hello或error,将其赋值给形参

  • @RequestParam(value="传递的参数名",defaultValue="没有传递参数时的默认值")

  • 该注解写在某个方法的某个参数上

  • 用于获取提交的数据,可以设置默认值在没有提交数据时使用

解决提交数据时的中文乱码

使用过滤器解决中文乱码。

在web.xml中配置spring-web提供的CharaterEncodingFilter过滤器

<!--定文解决中文乱码的过器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>

将数据保存到作用域中

  • 在controller中的某个方法的参数列表里添加Model参数

  • 调用Model对象的addAttribute(String str,Object obj)方法, 将某个obj对象保存在request作用域中, 命名为str

//将数据保存到作用域中
@RequestMapping("/queryAll")
public String queryAll(Model model){ArrayList list = new ArrayList<>();list.add("adsh ");list.add(1212);list.add(true);list.add("米西米西");//将List保存到请求中model.addAttribute("list",list);return "welcome";
}

在controller中的某个方法的参数列表中添加ModelAndView参数,同时将该方法的返回值设置为ModelAndView类型。

  • 使用ModelAndView对象调用addObject(String str,Object obj),将某个obj对象保存在request作用域中,命名为str

  • 使用ModelAndView对象调用setViewName(String viewName),跳转到viewName页面

@Controller
@RequestMapping(path = "/hero")
//如果要将数据保存到session中,使用该注解定义session中对象的名称
@SessionAttributes({"str1","str2"})
public class HeroController {@Autowiredprivate HeroService heroService;@RequestMapping("/queryAll")public String queryAll(Model model) {List<Hero> heroes = heroService.queryAll();model.addAttribute("list", heroes);return "heroList";}@RequestMapping("/showAll")public ModelAndView queryAll(ModelAndView mav) {List<Hero> heroList = heroService.queryAll();//保存查询出的对象到请求中,命名为list,默认保存在request作用域中mav.addObject("list", heroList);// mav.addObject("str1", heroList);//保存在session中//设置要跳转的页面mav.setViewName("heroList");return mav;}}

数据都是保存在request作用域中,在页面中使用JSP内置对象或EL获取

如果要保存到session中,需要在类上加入@SessionAttributes({"str1","str2"})注解,str1,str2表示保存到session中的对象的名称,再在方法中,使用Model对象的addAttribute(String str,Object obj)将其保存在session中

SpringMVC中的跳转

控制层跳转到某个jsp页面

  • 在控制层中定义方法,这种方式跳转属于请求转发

  • 如果要使用重定向,在页面名之前添加"redirect:"

@RequestMapping("/he11o")
public String hello(){return "hello";//hello是一个界面,转发return "redirect:hello";//重定向
}//第二种
@RequestMapping("/he11o")
public ModelAndView hello(ModelAndView mav){mav.setViewName("hello");return mav;
}
  • 在springmvc配置文件中

<mvc:view-controller path="请求映射" view-name="页面名称"></mvc:view-controller><!--设置请求视图映射,跳转到一个页面-->
<!--该标签无法@RequestMapping共存-->
<mvc:view-controller path="/" view-name="welcome"></mvc:view-controller>
<!--如果要同时使用@Reques tMapping和mvc :view-controller标签,需要加入以下标签,该标签位于xmIns :mvc= "http://www. springframework. org/schema/mvc 1-->
<mvc:annotation-driven></mvc:annotation-driven>

控制层跳转到另一个控制层中

  • 方法的返回值为"redirect/forward:另一 个控制层中方法的映射名"

@RequestMapping("/he11o")
public String hello(){return "forword:hello";//使用请求转发的方式,跳转到映射名为hero的控制层return "redirect:hello";//使用重定向的方式,跳转到映射名为hero的控制层
}

JSP页面跳转另一个JSP页面

  • 当前项目中JSP页面搜在WEB-INF目录下,无法直接访问,a标签同样如此,只能通过controller控制层跳转页面

@Controller
public class ToPageController {@RequestMapping("/")public String toIndex(){return "redirect:/hero/queryAll";}// 这个方法的作用:会将请求中第一个/后的单词截取出来命名为ath赋值给参数page//如localhost:8080/web/hero, 就会识别出hero,return "hero";//通过视图解析器,就会跳转到/WEB-INF/pages/hero.jsp页面@RequestMapping("/{path}")public String toPage(@PathVariable("path") String page){return page;}
}

这时在页面中这样跳转

<%--SpringMVC中如果要跳转页面,必须途径controller,不能使用a标签跳转--%>
<%--这个路径实际是/项目名/addHero,会截取addHero,跳转到addHero. jsp--%>
<a href="${pageContext.request.contextPath}/addHero">添加</a>

文件上传

使用apche提供的通用文件上传组件实现

1.导入所需依赖

<!--文件上传-->
<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.4</version>
</dependency>

2.向spring容器中注入上传文件的核心类

<!--注入上传文件的核心类:通用多部件解析器CommonsMultipartResolver-->
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver"><!--设置上传的单个文件最大字节:10MB=1024*1024*10--><property name="maxUploadSizePerFile" value="10485760"></property>
</bean>

3.上传页面的表单

<!--.上传的表单控件使用file-->
<!--提交方式只能为post-->
<!--添tenctype= "multipart/form-data"属性-->
<form method="post" enctype="multipart/form-data" action="./admin/upload">请选择图片<input type="file" name="uploadFile"><input type="submit" value="上传">
</form>

4.控制层获取上传的文件

@Controller
@RequestMapping("/admin")
public class UploadController {@RequestMapping("/upload")public String upload(MultipartFile uploadFile) throws IOException {//uploadFile就是上传的文件对象//获取上传的文件名String oldName = uploadFile.getOriginalFilename();//得到源文件的后缀名String prefix = oldName.substring(oldName.lastIndexOf("."));//有可能不同的人上传的文件名相同,所以获取源文件的后缴后,生成一个随机文件名, 拼接新文件名。String newName = UUID.randomUUID() + prefix;//创建一个文件File对象File file = new File("D:\\idea上传图片",newName);System.out.println(file);//将文件写入硬盘中uploadFile.transferTo(file);return "welcome";}
}

配置Spring+SpringMVC时用到的关键类

  • spring全局监听器(web.xml)

  • ContextLoaderListener

  • 配置springMVC内部资源视图解析器(在Springmvc配置文件中)

  • InternalResourceViewResolver

  • 配置springMVC请求分发Servlet(web.xml)

  • DispatcherServlet

  • 字符编码格式过滤器(web.xml)

  • CharacterEncodingFilter

MyBatis

一个半自动化的ORM框架。原本叫做ibatis, 后来升级改名为MyBatis。

MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。

使用XML文件或注解的形式,将SQL语句映射为持久层(dao层)中的方法

特点

  • 方便

  • 简化JDBC

  • 解除SQL语句与业务代码的耦合

  • sql和Java代码分离,sql写在xml中,方便扩展维护

  • 支持动态SQL

  • 不同的情况下构造不同的sql

  • 主流

  • SSM中的M

SSM项目搭建

流程

  • 1.创建基于Maven的webapp项目

  • 2.修改web.xml版本为4.0,创建Java、resoureces目录、项目包目录、web-inf下的页面目录

  • 3.导入依赖

  • spring-webmvc

  • mybatis

  • mysql

  • mybatis-spring

  • druid

  • spring-jdbc

  • jstl

  • 4.配置Spring

  • 创建application.xml

  • 扫描项目根包

  • 配置web.xml

  • 设置全局参数:<context-param>,读取application.xml文件

  • 设置全局监听器:ContextLoaderListener,初始化spring容器

  • 5.配置SpringMVC

  • 创建springmvc.xml

  • 扫描控制层所在包

  • 设置内部资源视图解析器:InternalResourceViewResolver,设置前后缀

  • 配置web.xml

  • 设置请求分发器:DispatcherServlet,在其中读取springmvc.xml配置文件

  • 过滤器解决请求中文乱码:CharacterEncodingFilter

  • 6.配置MyBatis

  • 创建mybatis-config.xml(官网模板)

  • 在application.xml中注入

  • 数据库连接池Druid:DruidDaJaSource

  • SQL会话工厂:SqISessionFactoryBean

  • 映射扫描配置器: MapperScannerConfigurer

  • 7.执行sql语句

  • 创建dao层接口,定义方法

  • 在resoureces下创建mapper目录,创建sql映射文件xx.xml(官网模板),在其中定义sql语句

实现步骤

1.创建基于Maven的webapp项目

2.修改web.xml版本为4.0,创建Java、resoureces目录、项目包目录、web-inf下的页面目录

3.导入依赖

<dependencies><!--jstl--><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><!--springWebMVC--><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.23</version></dependency><!--mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.11</version></dependency><!--spring集成Mybatis--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.7</version></dependency><!--数据库连接池Druid--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version></dependency><!--spring集成JDBC--><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.23</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.31</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency>
</dependencies>

4.配置spring

  • 在resoureces下创建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"><!--扫描使用了SpringMVC注解的根包--><context:component-scan base-package="com.hqyj.ssm"></context:component-scan></beans>
  • 在web.xml中配置监听器和全局参数

<?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><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:application.xml</param-value></context-param>
</web-app>

5.配置SpringMVC

  • 在resoureces下创建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"><!--扫描使用了SpringMVC注解的根包--><context:component-scan base-package="com.hqyj.ssm01.controller"></context:component-scan><!--设置内部资源视图解析器--><bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver"><!--设置页面前缀和后缀--><property name="prefix" value="/WEB-INF/pages/"></property><property name="suffix" value=".jsp"></property></bean>
</beans>
  • 在web.xml中配置DispatcherServlet和中文乱码过滤器

<?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><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:application.xml</param-value>
</context-param><!--配置DispatcherServlet-->
<servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 初始化参数读取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><url-pattern>/</url-pattern>
</servlet-mapping><!--过滤器解决请求中文乱码--><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>
</web-app>

6.配置MyBatis

  • 在resoureces下创建mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!--设置--><settings><!--开启驼峰命名自动映射--><!--<setting name="mapUnderscoreToCamelCase" value="true"/>--><!--开启SQL日志--><setting name="logImpl" value="STDOUT_LOGGING"/></settings>
</configuration>
  • 在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"><!--扫描使用了SpringMVC注解的根包--><context:component-scan base-package="com.hqyj.ssm"></context:component-scan><!--注入Druid数据源--><bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource"><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property><property name="url" value="jdbc:mysql://localhost:3306/gamedb?serverTimezone=Asia/Shanghai"></property><property name="username" value="root"></property><property name="password" value="123456"></property></bean><!--注入mybatis核心对象SqlSessionFactoryBean--><bean class="org.mybatis.spring.SqlSessionFactoryBean" id="SqlSessionFactory"><!--设置数据源--><property name="dataSource" ref="dataSource"></property><!--设置MyBatis配置文件路径--><property name="configLocation" value="classpath:mybatis-config.xml"></property><!--设置mybatis的sql映射文件路径--><property name="mapperLocations" value="classpath:mapper/*.xml"></property></bean><!--扫描项目中的dao层目录--><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><!--设置MyBatis核心对象SqlSessionFactoryBean的名字--><property name="sqlSessionFactoryBeanName" value="SqlSessionFactory"></property><!--dao层根包--><property name="basePackage" value="com.hqyj.ssm.dao"></property></bean>
</beans>

7.执行SQL

package com.hqyj.ssm.entity;public class Hero {private int id;private String name;private String position;private String sex;private int price;private String shelf_date;@Overridepublic String toString() {return "{编号:" + id + ",名称:" + name + ",位置:" + position + ",性别:" + sex + ",价格:" + price + ",上架日期:" + shelf_date + "}";}
//省略了setter/getter方法

dao层接口

//使用MyBatis时,数据访问层/持久层/dao层,只需定义为接口
@Repository
public interface HeroDao {//查询所有List<Hero> queryAll();
}

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")public String queryAll(Model model) {List<Hero> list = heroService.queryAll();model.addAttribute("list",list);System.out.println(list);return "heroList";}//和queryAll作用一致/*public ModelAndView queryAll(ModelAndView mac) {List<Hero> list = heroService.queryAll();mac.addObject("list",list);mac.setViewName("heroList");System.out.println(list);return mac;}*/
}

在resources下的mapper目录下,创建sql映射文件,命名通常为"实体Mapper",如HeroMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace是该映射文件对应的dao层接口全限定名-->
<mapper namespace="com.hqyj.ssm.dao.HeroDao"><!--查询select标签--><!--id对应dao层中的某个方法名--><!--如果实体类中的属性名和表中的字段名一致,加入resultType属性,设置实体的全限定名--><select id="queryAll" resultType="com.hqyj.ssm.entity.Hero">select * from hero</select><!--表中字段和实体类中字段不同使用下列方法--><!--该标签用于给指定的实体类设置返回结果集映射--><!--id属性自定义该映射名称--><!--id属性自定义该映射名称--><!--type属性指定实体类-->
<!--    <resultMap id="heroMap" type="com.hqyj.ssm.entity.Hero">--><!--主键字段用id标签,其他字段用result标签--><!--id和result标签都有两个属性property表示实体类中的属性名,column表示表中的字段名-->
<!--        <id property="id" column="id"></id>-->
<!--        <result column="price" property="jiage"></result>--><!--如果遇到下划线转驼峰命名,无需在这里自定义映射,可以在mybatis 的配置文件中设置开启驼峰命名映外-->
<!--    </resultMap>--><!-- 如果实体中的属性和表中的字段名不一致,使用resultMap属性设置自定义的结果集映射-->
<!--    <select id="queryAll" resultMap="heroMap">-->
<!--        select * from hero-->
<!--    </select>-->
</mapper>

heroList.jsp页面

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>Title</title><style>table {border-collapse: collapse;margin: 30px auto;}td, th {width: 130px;height: 30px;border: 1px solid darkorange;text-align: center;}</style>
</head>
<body>
<table><tr><th>英雄编号</th><th>英雄名称</th><th>英雄位置</th><th>英雄性别</th><th>英雄价格</th><th>上架日期</th></tr><c:forEach items="${list}" var="hero"><tr><td>${hero.id}</td><td>${hero.name}</td><td>${hero.position}</td><td>${hero.sex}</td><td>${hero.price}</td><td>${hero.shelf_date}</td></tr></c:forEach>
</table>
</body>
</html>

补充

通过db.properties文件保存连接数据库的信息

.properties文件称为属性文件,其中的数据以键值对(key=value)的形式保存。

  • 在resources目录下新建db.properties文件

DB_DRIVER_CLASS_NAME=com.mysql.cj.jdbc.Driver
DB_URL=jdbc:mysql://localhost:3306/bookdb?serverTimezone=Asia/Shanghai
DB_USERNAME=root
DB_PASSWORD=123456
  • 在application.xml中读取properties文件

<!--读取properties文件-->
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
  • 读取时使用EL表达式访问其中的键

<!--Druid数据源-->
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource"><property name="driverClassName" value="${DB_DRIVER_CLASS_NAME}"></property><property name="url" value="${DB_URL}"></property><property name="username" value="${DB_USERNAME}"></property><property name="password" value="${DB_PASSWORD}"></property>
</bean>

MyBatis配置文件常用设置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!--设置--><settings><!--开启驼峰命名映射--><setting name="mapUnderscoreToCamelCase" value="true"/><!--开启SQL日志--><setting name="logImpl" value="STDOUT_LOGGING"/></settings>
</configuration>

MyBatis基本增删改查

实体类:

package com.hqyj.ssm2.entity;import org.omg.CORBA.PRIVATE_MEMBER;public class BookInfo {private int bookId;private int TypeId;private String bookName;private String bookAuthor;private int bookPrice;private int bookNum;private String publisherDate;private String bookImg;//用于修改类型、价格和库存public BookInfo(int bookId, int typeId, int bookPrice, int bookNum) {this.bookId = bookId;TypeId = typeId;this.bookPrice = bookPrice;this.bookNum = bookNum;}//用于全部修改public BookInfo(int bookId, int typeId, String bookName, String bookAuthor, int bookPrice, int bookNum, String publisherDate, String bookImg) {this.bookId = bookId;TypeId = typeId;this.bookName = bookName;this.bookAuthor = bookAuthor;this.bookPrice = bookPrice;this.bookNum = bookNum;this.publisherDate = publisherDate;this.bookImg = bookImg;}public BookInfo() {}//忽略setter/getter/toString方法
}

dao层

@Repository
public interface BookInfoDao {//查询所有List<BookInfo> queryAll();//根据id删除int delete(int id);//添加int insert(BookInfo bookInfo);//根据id查找BookInfo findById(int no);//修改,参数为一个完整的修改对象//全部都可以修改// int update(BookInfo bookInfo);//如果dao人中某个方法中有多个参数,需要给任个多数添加@Param("参数名")注解,给该参数命名//命名后,才能在mybatis的sql映射文件中使用该参数,即#{参数行}//如这里的newPrice,在sql中#{newPrice}获取//只修改类型、价格和库存int update(@Param("newTypeId") int typeId,@Param("newPrice") int bookPrice, @Param("newNum") int bookNum, @Param("updateId") int bookId);
}

service层

@Service
public class BookInfoService {@Autowiredprivate BookInfoDao bookInfoDao;//查询所有public List<BookInfo> queryAll(){return bookInfoDao.queryAll();}//根据id删除public boolean delete(int id){return bookInfoDao.delete(id)>0;}//添加public boolean insert(BookInfo bookInfo){return bookInfoDao.insert(bookInfo)>0;}//根据id查找public BookInfo findById(int no){return bookInfoDao.findById(no);}//修改全部/*public boolean update(BookInfo bookInfo){return bookInfoDao.update(bookInfo)>0;}*///只修改类型、价格和库存public boolean update(int typeId,int bookPrice,int bookNum,int bookId){return bookInfoDao.update(typeId, bookPrice, bookNum, bookId)>0;}
}

controller层

@Controller
@RequestMapping("/bookInfo")
public class BookInfoController {@Autowiredprivate BookInfoService bookInfoService;//注入BookTypeService,用于获取所有的图书类型@Autowiredprivate BookTypeService bookTypeService;//查询所有@RequestMapping("/queryAll")public String queryAll(Model model) {List<BookInfo> list = bookInfoService.queryAll();model.addAttribute("list", list);return "bookInfoList";}//根据id删除@RequestMapping("/delete")public String delete(int id) {if (bookInfoService.delete(id)) {return "redirect:queryAll";}return "error";}//添加@RequestMapping("/insert")//如果表单提交的参数那方法的形参名一致, 自动获取并赋值//如果表单提交的所有参数正好是一个实体类对象,可以用对应的实体类对象获取public String insert(BookInfo bookInfo) {// System.out.println(bookInfo);if (bookInfoService.insert(bookInfo)) {return "redirect:queryAll";}return "error";}@RequestMapping("/findById")public  String  findById(@RequestParam("id") int no, Model model){//查询对应的图书信息BookInfo byId = bookInfoService.findById(no);model.addAttribute("book",byId);//查询所有图书的类型List<BookType> bookTypes = bookTypeService.queryAll();model.addAttribute("btList",bookTypes);return "bookEdit";}//全部都可以修改/*@RequestMapping("/update")public String update(BookInfo bookInfo){if (bookInfoService.update(bookInfo)) {return "redirect:queryAll";}return "error";}*/@RequestMapping("/update")public String update(int typeId,int bookPrice,int bookNum,int bookId){if (bookInfoService.update(typeId, bookPrice, bookNum, bookId)) {return "redirect:queryAll";}return "error";}
}

sql映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hqyj.ssm2.dao.BookInfoDao"><select id="queryAll" resultType="com.hqyj.ssm2.entity.BookInfo">select * from book_info</select><delete id="delete">delete from book_info where book_id=#{id}</delete><insert id="insert">insert into book_infovalues(null,#{typeId},#{bookName},#{bookAuthor},#{bookPrice},#{bookNum},#{publisherDate},#{bookImg})</insert><select id="findById" resultType="com.hqyj.ssm2.entity.BookInfo">select * from book_info where book_id=#{no}</select><!--全部都可以修改--><!--<update id="update">update book_info settype_id=#{typeId},book_name=#{bookName},book_author=#{bookAuthor},book_price=#{bookPrice},book_num=#{bookNum},publisher_date=#{publisherDate},book_img=#{bookImg}where book_id=#{bookId}</update>--><!--只修改类型、库存、价格--><update id="update">update book_info set type_id=#{newTypeId},book_price=#{newPrice},book_num=#{newNum} where book_id=#{updateId}</update>
</mapper>

SpringBoot

特点

  • 内置了Tomcat服务器,不需要部署项目到Tomcat中

  • 内置了数据源Hikair

  • 减少了jar文件依赖的配置

  • SpringBoot中的配置文件可以使用yml格式文件,代替xml

创建SpringBoot项目并选择web依赖

依赖可以创建项目时添加,也可以创建好项目之后添加

热部署和Lombok依赖

<!--热部署-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><version>2.7.8</version>
</dependency><!--Lombox-->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version><scope>provided</scope>
</dependency>

在某个类上添加注解

lombok常用注解

作用

@AllArgsConstructor

自动生成全参构造方法

@Data

该注解相当于一下注解的和

@NoArgsConstructor

自动生成无参构造方法

@Setter

生成setter方法

@Getter

生成getter方法

@ToString

生成toString方法

@EqualsAndHashCode

自动生成hashcode以及equals方法

SpringBoot+MyBatis实现单表查询

1.创建好SpringBoot项目

最好在创建的时候选择以下依赖

  • spring-web(必选)

  • lombok

  • spring-devtools

  • springboot集成mybatis

  • mysql驱动

2.在pom.xml中添加mybatis集成SpringBoot依赖和数据库驱动

<!--springboot集成mybatis-->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.3.0</version>
</dependency><!--mysql-->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.31</version>
</dependency>

3.在springboot配置文件application.properties中

#properties文件称为属性文件,数据以键值对的形式保存   键=值#项目端口号
server.port=8088
#项目上下文路径:http://localhost:8088/springboot/
server.servlet.context-path=/springboot
#mybatis配置#开启驼峰映射
mybatis.configuration.map-underscore-to-camel-case=true#sql日志:打印sql语句
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#扫描mybatis的sql映射文件
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=123456

mybatis的sql映射文件模板

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--设置该文件对应的dao层接口全限定名-->
<mapper namespace="com.hqyj.springboot.mapper.HeroMapper"></mapper>

4.根据数据表创建实体类、mapper(dao)层接口、service、controller

表(Hero):id(编号) name(名称) position(位置) sex(性别) price(价格) shelf_date(上架日期)

实体类
//该注解会自动生成getter/setter/toString/equals/hashCode方法
@Data
public class Hero {private Integer id;private String name;private String position;private String sex;private Integer price;private String shelfDate;
}
mapper层接口
@Repository
public interface HeroMapper {List<Hero> queryAll();
}
mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hqyj.springboot.mapper.HeroMapper"><select id="queryAll" resultType="com.hqyj.springboot.entity.Hero">select * from hero</select>
</mapper>
service层
@Service
public class HeroService{@Autowiredprivate HeroMapper heroMapper;public List<Hero> queryAll(){return heroMapper.queryAll();}
}
controller层
@Controller
@RequestMapping("/hero")
public class HeroController {@Autowiredprivate HeroService heroService;@RequestMapping("/queryAll")@ResponseBodypublic List<Hero> queryAll(){return heroService.queryAll();}
}

5.在SpringBoot的启动类上加入@MapperScan注解,去扫描mapper层所在目录

@SpringBootApplication
//扫描mapper(dao)层所在包
@MapperScan("com.hqyj.springboot.mapper")
public class SpringbootApplication {public static void main(String[] args) {SpringApplication.run(SpringbootApplication.class, args);}
}

MyBatisPlus

MyBatis-Plus (简称MP)是一个MyBatis的增强工具, 在MyBatis的基础上只做增强不做改变,为简化开发、提高效率而生。

特点

  • 只需简单的配置,就能实现对单表的CURD。

  • 其核心有两个接口:BaseMapper和IService

  • BaseMapper中封装了大量数据访问层的方法

  • Iservice中封装了大量业务流程层的方法

SpringBoot+MyBatisPlus

1.创建SpringBoot项目

创建时添加依赖

  • devtools

  • lombok

  • spring-web

  • mysql Driver

2.导入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=123456# 开启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="字段名")

  • 主键字段对应的属性,需要加入@Tableld注解,在数据库中也要将主键设置为自增

  • @Tableld(type = ldType.AUTO)表示主键自增,在数据库也要将主键设置为自增

  • @TableId(type = IdType.ASSIGN_ID)表示使用"雪花算法"(根据时间和机器特征码)生成一个id

  • @TableId(type = IdType.ASSIGN_UUID)表示使用UUID生成一个随机字符串id

@Data
public class Hero {private Integer id;//如果属性和字段名不一致,需添加下列注解@TableField(value = "name")private String heroName;private String position;private String sex;private Integer price;private String shelfDate;
}

5.编写数据访问层接口

可以不用写@Repository,继承BaseMapper接口,设置泛型

package com.hqyj.sbmp1.Mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hqyj.sbmp1.entity.Hero;/*数据访问层可以称为dao层或mapper层
*可以不用加@Repository注解
* */
public interface HeroMapper extends BaseMapper<Hero> {}

6.在SpringBoot启动类中,扫描数据访问层所在包

package com.hqyj.sbmp1;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@MapperScan("com.hqyj.sbmp1.mapper")
public class Sbmp1Application {public static void main(String[] args) {SpringApplication.run(Sbmp1Application.class, args);}}

BashMapper接口

BashMapper接口中定义了常用的增删改查方法,通常在数据访问层接口中继承该接口,就能直接使用其中所有方法

使用

package com.hqyj.sbmp1.Mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hqyj.sbmp1.entity.Hero;/*数据访问层可以称为dao层或mapper层
*可以不用加@Repository注解
* */
public interface HeroMapper extends BaseMapper<Hero> {}

BashMapper接口中的常用方法

方法名

参数

作用

selectList(Wrapper wrapper)

条件构造器

条件查询集合,如果实参为null表示查询所有,返回List集合

selectById(Serializable id)

主键

根据主键查询单个对象,返回单个对象

selectByOne(Wrapper wrapper)

条件构造器

条件查询单个对象,返回单个对象

insert(T entity)

实体对象

添加

updateById(T entity)

实体对象

根据实体对象单个修改,对象必须至少有一个属性

update(T entity,Wrapper wrapper)

实体对象和条件构造器

根据条件修改全部,对象必须至少有一个属性

deleteById(Serializable id/T entity)

主键/实体对象

根据主键删除单个对象

deleteBatchlds(Collection col)

主键集合

根据集合删除

delete(Wrapper wrapper)

条件构造器

根据条件删除

IService接口

为了减少业务逻辑层的代码,并对BaseMapper进行拓展

通常在业务流程层中继承该接口,就能直接使用其中的所有方法

使用

  • 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)

根据条件查询,如果参数为null,表示查询所有,会导致异常

save(T entity)

添加

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接口中有很多方法都有这个参数,表示一个条件构造器对象。

如果该参数实际传递的值为nll,表示没有任何条件

这个Wrapper是一个抽象类,如果想要带条件,就要创建一个该类的子类对象。

常用子类为QueryWrapper和UpdateWrapper,

查询是创建QueryWrapper对象,更新时创建UpdateWrapper,实际使用无区别。

Wrapper对象带参数

Wrapper wrapper = new QueryWrapper<>(T entity);

Wrapper构造方法的参数如果是一个实体对象,只要该对象的属性不为空,就会将所有属性用and拼接起来作为条件

这种适合已知某个字段为某个值时使用。

@Test
void test1(){//创建实体对象,只带两个属性值Hero hero = new Hero();hero.setHeroName("杨戬");hero.setPosition("战士");//创建一个带实体参数的条件构造器对象Wrapper<Hero> wrapper = new QueryWrapper<>(hero);System.out.println(heroService.getOne(wrapper));
}

Wrapper对象不带参数

Wrapper wrapper = new QueryWrapper<>();

当条件构造器不带参数时,就需要自定义条件。

这种适用于自定义查询条件

默认多个条件时,用and拼接

指定值或范围

//指定值或范围
@Test
void test2(){/**eq(String column,Object val)   equals          column=val*ne(String column,Object val)   not equals      column<>val*lt(String column,Object val)   less then       column<val*gt(String column,Object val)   great then      column>val*le(String column,Object val)   less equals     column<=val*ge(String column,Object val)   great equals    column>=val*between(String column,Object val1,0bject vol2) between and     column between val1 and vol2*notBetween(String column,Object val1,0bject vol2) not between and   column not between val1 and vol2* *///创建一个不带实体参数的条件构造器对象QueryWrapper<Hero> wrapper = new QueryWrapper<>();//自定义条件:指定值     查询性别为男的数据wrapper.eq("sex","男");//查询性别不为男的数据// wrapper.ne("sex","男");//查询价格在10000-19000的记录wrapper.between("price",10000,19000);//查询价格小于18888的战士,多个条件默认用and拼接wrapper.lt("price",18888);wrapper.eq("position","战士");//查询性别为女或价格大于8000//or()方法会将前后的条件使用or拼接wrapper.gt("price",8000);wrapper.or();wrapper.eq("sex","女");//查询性别为男的战士或价格大于13000的法师wrapper.eq("sex","男");wrapper.eq("position","战士");wrapper.or();wrapper.eq("position","法师");wrapper.gt("price",13000);//采用链式写法wrapper.eq("sex","男").eq("position","战士").or().eq("position","法师").gt("price",13000);heroService.list(wrapper).forEach(System.out::println);
}

空值和模糊查询

//空值
@Test
void test3(){/**isNulL(String column)                      column is null* isNotNull(String column)                  column is not null* like(String column, 0bject vol)           column like '%val%'* likeLeft(String column, 0bject vol)       column like '%val'* likeRight(String column, 0bject vol)      column like 'val%'* notLike(String column, 0bject vol)        column not like '%val%'* notLikeLeft(String column, 0bject vol)    column not like '%val'* notLikeRight(String column, 0bject vol)   column not like 'val%'* */QueryWrapper<Hero> wrapper = new QueryWrapper<>();//字段为空wrapper.isNull("shelf_date");//带有指定关键字wrapper.like("name","孙");//以指定关键字结尾wrapper.likeLeft("name","空");//以指定关键字开头wrapper.likeRight("name","孙");//查询名字中带有孙字且上架时间为空的数据wrapper.like("name","孙");wrapper.isNull("shelf_date");heroService.list(wrapper).forEach(System.out::println);
}

集合和排序

/*集合和排序*/
@Test
void test4(){/*集合*in(String column, 0bject... vals)          column in (val1, val2...)*in(String column, Collection vals)         column in (val1, val2...)* notIn(String column, 0bject... vals)      column not in (val1, val2...)*notIn(String column, Collection vals)      column not in (val1, val2...)** 排序* orderByAsc(String column)         order by column asC* orderByDesc(String column)        order by coLumn desc* */QueryWrapper<Hero> wrapper = new QueryWrapper<>();//职业为战士或法师或射手wrapper.eq("position","战士").or().eq("position","法师").or().eq("position","射手");wrapper.in("position","战士","法师","射手");//集合wrapper.in("position", Arrays.asList("战士","法师","射手"));//排序//所有男性角色,按价格降序wrapper.eq("sex","男").orderByDesc("price");heroService.list(wrapper).forEach(System.out::println);
}

分组聚合

分组通常会和聚合函数(count,sum,max,min,avg)一起使用,但MyBatisPlus中没有现有的聚合函数。

需要使用select(String...Fields)自定义查询字段

@Test
void test5(){/** select(String... fields)      select field1,field2...* groupBy(String column)        group by column* */QueryWrapper<Hero> wrapper = new QueryWrapper<>();//无参数时,查询所有字段wrapper.select();//查询指定字段wrapper.select("name");//使用聚合函数统计数量wrapper.select("count(id)");//查询不同性别的人数//sql语句:select sex,count(id) from hero group by sexwrapper.select("sex","count(id)");wrapper.groupBy("sex");//根据指定字段分组//根据定位分组,查询值为法师、战士和射手的人数,按人数降序//select position,count(id) from hero where position in('法师','战士','射手') group by position order by count(id) descwrapper.select("position","count(id)").in("position","法师","战士","射手").groupBy("position").orderByDesc("count(id)");//当前的sql语句查询的结果是一个订制数据,如查询总数只会得到一个数据,所以使用listMaps方法List<Map<String, Object>> maps = heroService.listMaps(wrapper);System.out.println(maps);
}

分页查询

MyBatisPlus中集成了分页功能,只需在项目的启动类中注入一个分页拦截器对象

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){//创建一个MybatisPlusInterceptor对象MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();//通过拦截器对象添加分页拦截器对象,设置数据库类型interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));return interceptor;
}

无条件分页查询

@Test
void test1() {//无条件分页查询//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());
}

条件分页查询

@Test
void test2(){Page<Hero> pageInfo = new Page<>(1, 5);QueryWrapper<Hero> wrapper = new QueryWrapper<>();//分页查询所有法师pageInfo = heroService.page(pageInfo,wrapper.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", "123456").globalConfig(builder -> {builder.author("HQYJ") // 设置作者,生成文件的注释里的作者.outputDir("D:\\idea培训文件\\Spring相关内容\\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为基础,在HTML 中嵌入ava代码。

可以当作HTML页面打开查看页面内容

用法

1.添加依赖

<!-- thymeleaf页面模板引擎-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId><version>2.7.3</version>
</dependency>

2.在temlates目录下创建一个HTML页面

在页面的<html>标签中,加入属性

3.thymeleaf具体使用

  • 双标签中的输出变量:th:text

<h1 th:text="${保存在作用域中的变量}">这里显示str变量</h1>
<h1 th:text="${str}">这里显示str变量</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>

超链接获取全局路径:th:href="@{/}"

  • 不带参数

<link th:href="@{/bootstrap-3.4.1-dist/css/bootstrap.css}" rel="stylesheet">
  • 带参数

<a th:href="@{'/hero/delete?id='+${hero.id}}">删除</a>
  • 表单提交路径:th:action="@{/}"

<form method="post" th:action="@{/hero/insert}"></form>
  • 判断:th:if

<h1 th:if="判断逻辑">用户信息</h1>
<h1 th:if="${userInfo.userName==null}">请登录</h1>
  • 选中单选按钮和复选框:th:checked

<input type="radio" name="quesAns" value="a" th:checked="${question.quesAns=='a'}"> A
<input type="radio" name="quesAns" value="b" th:checked="${question.quesAns eq 'b'}"> B
<input type="radio" name="quesAns" value="c" th:checked="${question.quesAns=='c'}"> C
  • 选中下拉菜单:th:selected

<div class="col-sm-10"><select class="form-control" name="qcId"><option th:selected="${qc.qcId eq question.qcId}" th:each="qc:${qcList}" th:value="${qc.qcId}"th:text="${qc.qcName}"></option></select>
</div>
  • src属性:th:src

<script th:src="@{/bootstrap-3.4.1-dist/js/jquery-3.6.2.min.js}"></script>
  • 内联表达式

Thymeleaf页面中的内联表达式

[[]]之间的表达式在Thymeleaf中称为内联表达式,可以用在script标签中拼接EL表达式

要在script标签中加入th:inline="javascript"属性

<script th:inline="javascript">$(function () {//遍历页码$(".pno").each(function () {//如果页码和当前页码一致,高度显示if ($(this).text() == [[${pageInfo.current}]]) {$(this).addClass("active");}});});
</script>

Spring Data JPA

是一套Java访问数据库的规范,由一系列接口和抽象类构成。

SpringBoot集成Spring Data JPA

1.创建项目选择依赖

  • Lombok

  • Spring Web

  • MySQL Driver

  • Spring Data JPA

  • Spring Boot devTools

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=123456# 设置数据库类型
spring.jpa.database=mysql
# 打印sql语句
spring.jpa.show-sql=true

3.创建实体类

  • 类上添加@Entity注解

  • 主键属性上

  • @Id注解标明主键

  • @GeneratedValue(strategy = GenerationTye.IDENTITY设置主键生成策略,数据库设置为自增

  • 其他属性与字段名不一致或驼峰命名法

  • 如果不相同,使用@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_info")private Integer price;private Integer bookNum;private String publisherDate;private String bookImg;
}

4.数据访问层接口

  • 类上加@Repository注解

  • 继承paRepository<实体类型,主键类型>接口

@Repository
public interface BookInfoDao extends JpaRepository<BookInfo,Integer> {}

5.单元测试类

@SpringBootTest
class SpringbootjpaApplicationTests {@Autowiredprivate BookInfoDao bookInfoDao;@Testvoid contextLoads() {//查询所有List<BookInfo> list = bookInfoDao.findAll();list.forEach(System.out::println);}@Testvoid insert(){//添加BookInfo bookInfo = new BookInfo();bookInfo.setBookName("测试");bookInfo.setTypeId(1);bookInfo.setBookAuthor("测试");bookInfo.setBookNum(200);bookInfo.setPrice(40);//save()方法调用时,如果对象中没有主键或主键值不存在,作为添加使用BookInfo save = bookInfoDao.save(bookInfo);//添加成功后,会自动获取主键自增的值System.out.println(save);}@Testvoid update(){//修改BookInfo bookInfo = new BookInfo();bookInfo.setBookName("xxxxxx");bookInfo.setTypeId(1);bookInfo.setBookAuthor("xxxx");bookInfo.setBookNum(200);bookInfo.setPrice(40);//save()方法调用时,如果对象中有主键且存在,作为修改使用BookInfo save = bookInfoDao.save(bookInfo);//修改成功后,返回修改后的对象System.out.println(save);}//删除@Testvoid delete(){//根据主键值删除,如果值不存在,会报错bookInfoDao.deleteById(1);//根据对象删除,如果对象中包含主键值则删除,如果没有值或不存在,不会报错BookInfo bookInfo = new BookInfo();bookInfo.setBookId(2);bookInfoDao.delete(bookInfo);}@Testvoid findOne(){//根据主键查询,返回值Optional类型Optional<BookInfo> byId = bookInfoDao.findById(3);//isPresent()如果为true,表示查询到了数据if (byId.isPresent()) {//get()将查询到的数据转换为对应的实体类BookInfo bookInfo = byId.get();System.out.println(bookInfo);}else {System.out.println("未查询到数据");}}
}

常用方法

方法

返回值

作用

findAll()

List<T>

查询所有数据

save(T entity)

T entity

添加或修改,如果不存在主键属性或主键值不存在,执行添加;如果存在主键属性且有该主键值,执行修改

delete(T entity)

void

根据对象删除。如果该对象中有主键属性且有该主键值,根据该主键值删除

findById(主键)

Optional<T>

根据主键值查询。返回的对象调用isPresent()结果为true, 表示查询到了数据,继续调用get)得到查询到的对象。

JPA进阶

分页查询

在数据访问层中调用findAll(Pageable pageable)方法,即可实现分页

参数Pageable是org.springframework.data.domain包中的一个接口,通过其实现类

PageReguest,调用静态方法of(int page,int size),当做Pageable对象使用。

这里的page从0开始为第一页

//分页查询
@Test
void queryByPage(){//PageRequest是Pageable的实现类调用PageRequest类中的静态方法of(int page,int size)//这里的page的值0表示第一页PageRequest of = PageRequest.of(0, 5);//调用findAll(Pageable pageable)方法,返回分页模型对象Page<BookInfo> pageInfo = bookInfoDao.findAll(of);//分页相关数据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中定义了queryAllById(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=?

Or/And

findByNameOrBookAuthor(String name,Strng author)findByNameAndBookAuthor(String name,Strng author)

book_name=? or book_author=?book_name=? and book_author=?

After/Before

findByBookPriceAfter(double number)findByBookPriceBefore(double number)

book_price>numberbook_price<number

GreatThan/LessThan

queryAllByBookNumGreaterThan(int num)queryAllByBookNumLessThan(int num)

book_num>numbook_num<num

GreatThanEqual/LessThanEqual

queryAllByBookNumGreaterThanEqual(int num)queryAllByBookNumLessThanEqual(int num)

book_num>=numbook_num<=num

Between

findByBookNumBetween(int min,int max)

book_num between min and max

IsNull/IsNotNull

findAllByPublisherDateIsNull()findAllByPublisherDateIsNotNull

publisher_date is nullpublisher_data is not null

Like/NotLike

getAllByBookNameLike(String keyword)getAllByBookNameNotLike(String keyword)

book_name like keywordbook_name not like keyword

Contains/NotContains

findByBookNameContains(String keyword)findByBookNameNotContains(String keyword)

book_name like '%keyword%'book_name not like '%keyword%'

StartsWith/EndsWith

findByBookNameStartsWith(String firstName)findByBookNameEndsWith(String endName)

book_name like 'firstName%'book_name like '%endName'

无条件排序:findAllByOrderBy字 段[Desc/Asc]

findAllByOrderByBookId()findAllByOrderByBookIdDesc()

order by book_id ascorder by book_id desc

有条件排序:findAllBy条件 OrderBy字段[Desc/Asc]

findAllByTypeIdOrderByBookIdDesc()findAllByTypeIdOrderByBookId()

type_id = ? order by book_id desctype_id = ? order by book_id

@Repository
public interface BookInfoDao extends JpaRepository<BookInfo, Integer> {//指定值查询//根据书名查询List<BookInfo> getAllByBookName(String x);//查询价格大于指定值   字段对应的属性名  After/GreaterThanList<BookInfo> findAllByPriceAfter(int price);//查询价格小于于指定值    字段对应的属性名  Before/LessThanList<BookInfo> findAllByPriceLessThan(int price);//查询库存大于等于指定值 GreaterThanEqualList<BookInfo> queryAllByBookNumGreaterThanEqual(int num);//查询库存在指定闭区间内 Between(int min,int max)List<BookInfo> findAllByBookNumBetween(int min, int max);//空值查询 null//查询出版日期为空  IsNull/IsNotNullList<BookInfo> findAllByPublisherDateIsNull();//书名中带有关键字 Like/NotLike 实参一定要使用%或_List<BookInfo> getAllByBookNameLike(String keyword);//作者名中带有关键字  Contains/NotContains 实参只需要关键字List<BookInfo> getAllByBookAuthorContains(String keyword);//指定作者的姓   指定开头/结尾  StartsWith/EndsWithList<BookInfo> getAllByBookAuthorStartsWith(String keyword);//查询所有数据,按价格降序    无条件排序 OrderBy字段[Desc/Asc]List<BookInfo> getAllByOrderByPriceDesc();//查询指定类型,按id降序List<BookInfo> getAllByTypeIdOrderByBookIdDesc(Integer typeId);//根据作者和书名的关键字分页查询Page<BookInfo> getAllByBookNameContainsOrBookAuthorContains(String nameKeyword,String authorKeyword,Pageable pageable);
}

条件分页查询

只需在定义方法时,将方法的返回值设置为Page类型,在参数中就如Pageable对象

//根据作者和书名的关键字分页查询
Page<BookInfo> getAllByBookNameContainsOrBookAuthorContains(String nameKeyword,String authorKeyword,Pageable pageable);
//根据作者和书名关键字分页查询
@Test
void test3(){Page<BookInfo> pageInfo = dao.getAllByBookNameContainsOrBookAuthorContains("龙","山",PageRequest.of(0,5));pageInfo.getContent().forEach(System.out::println);
}

聚合函数分组查询

自定义SQL

在数据访问层接口中的方法上,可以加入@Query注解,默认要使用HQL(Hibernate专用)格式的语句。

如果要使用原生的SQL语句,需要添加nativeQuery=true属性, 用value属性定义SQL语句

//测试查询
/*在JPA中,如果要使用自定义的SQL语句* nativeQuery = true 开启原生SQL语句* value="sqL语句"* */
//自定义sql:根据作者分类,查询作者的图书总量
@Query(nativeQuery=true,value="select book_author,count(book_id) from book_info group by book_author")
List testQuery();//根据类型分组,查询魅族图书的平均价格
@Query(nativeQuery=true,value="select type_id,avg(book_price) from book_info group by type_id")
List testQuery2();
//自定义sql:根据作者分类,查询作者的图书总量
@Test
void test5(){List list = dao.testQuery();//查询的结果为集合,集合中保存的是每一行数据for (Object row : list) {//每一行页数一个对象数组Object[] obj = (Object[]) row;//根据索引得到查询出的内容System.out.println(obj[0]+"-----"+obj[1]);}
}@Test
void test6(){List list = dao.testQuery2();for (Object object : list) {Object[] obj = (Object[]) object;System.out.println(obj[0]+"-----"+obj[1]);}
}

自定义SQL中带参数

SQL语句中的"XXX"表示参数

如果方法的形参名和xxx一致时直接使用,如果不一致,在形参上加入@Param注解设置形参名

//根据作者查询其图书总库存:select book_author,sum(book_num) from book_info where book_author='金庸'
/*使用":形参名"在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 test7(){List list = dao.testQuery3("金庸");for (Object object : list) {Object[] obj = (Object[]) object;System.out.println(obj[0]+"-----"+obj[1]);}
}

关联查询

主表:book_type

从表:book_info

//如果根据外键字段查询,方法名写为By外键实体类属性名_属性名
List<BookInfo> getAllByBt_TypeId(Integer typeId);
//根据图书类型查找书籍
List<BookInfo> bookInfos = dao.getAllByBt_TypeId(2);
bookInfos.forEach(System.out::println);

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

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

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

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

    框架 一套规范. 实际是他人实现的一系列接口和类的集合.通入导入对应框架的jar文件(maven项目导入对应的依赖),进行适当的配置,就能使用其中的所有内容. 开发者可以省去很多模板代码,如dao中的 ...

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

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

  4. 华清远见-重庆中心-前端技术总结/知识点梳理/个人总结/面试题解析

    HTML 1.1什么是HTML 超文本:有视频,音频,图片等,超越文本 超文本标记语言(Hyper Text Markup Language) 标记语言:有一套标签 1.2标签 是由<>包 ...

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

    花了两周多的时间对HTML.CSS.JavaScript和jQuery进行系统性的学习,学习完了后打算花一点时间对之前学习的内容进行复习巩固与总结,划分熟悉程度进行不同程度的梳理,顺便记录. 复习 H ...

  6. 华清远见-重庆中心-框架个人总结

    框架 一套规范. 实际是他人实现的一系列接口和类的集合.通入导入对应框架的jar文件(maven项目导入对应的依赖),进行适当的配置,就能使用其中的所有内容. 开发者可以省去很多模板代码,如dao中的 ...

  7. 华清远见重庆中心—JavaWeb技术总结/个人总结

    JavaWeb 网站 用户通过浏览器访问某个域名或ip后,浏览到的综合性页面. 实际是发布在服务器上的一个应用程序,通过浏览器访问. 网页 网站中的某张页面 静态页面:所有人看到的内容都一样 动态页面 ...

  8. 华清远见重庆中心-面向对象技术总结/个人总结

    Java中标识符的命名规则 标识符 类名.方法名.变量名统称为标识符 标识符命名规范 帕斯卡命名法 所有单词首字母大写 如Employee.ClassName.StudentInfomation 驼峰 ...

  9. 华清远见-重庆中心-JavaWeb技术总结

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

最新文章

  1. 60日均线操盘的三种入场点形态
  2. python语言需要英语非常好吗-Python用不好英语水平不够?这里有官方中文文档你看不看...
  3. dedecms织梦修改标题默认长度
  4. 9、MySQL系统变量(查看和修改)
  5. java编程笔记18 文件压缩与解压缩
  6. zookeeper zoo.cfg配置文件
  7. 小程序开发(6)-之自定义导航栏
  8. 我看中国软件---规模篇
  9. Qt文档阅读笔记-官方2D Painting Example实例解析
  10. html(7)盒子模型
  11. postgresql获取表最后更新时间(通过触发器将时间写入另外一张表)
  12. 什么是 “动态规划” , 用两个经典问题举例。
  13. 「thunar」给thunar增加搜索文件功能
  14. LINUX中错误 SELinux is disabled
  15. 在Android开发中如何移除EditText上的输入焦点
  16. 光波波长划分和无线电波频段划分
  17. 64位java没有javaw.exe_javaw.exe路径错误导致eclipse无法启动
  18. 再见了,我的黄色文件夹(内置福利)
  19. 一文带你深入了解,什么是深度学习及其工作原理
  20. 女星长发如雪 上演现代版白发魔女传(组图)

热门文章

  1. 计算机电源用什么端子,三菱PLC电源端子的接线方法图解
  2. AI智能阅读助力全栈开发-逐浪CMS语音辅助2.0发布
  3. [附源码]计算机毕业设计JAVA保险业务管理系统
  4. kicad 自动生成封装库_【工具】KiCad版本嘉立创SMT贴片库及问题说明
  5. 文献阅读笔记整理--ConvNext:A ConvNet for the 2020s
  6. 使用Arduino Leonardo开发板制作操纵杆游戏控制器
  7. VisionMaster标定板标定
  8. 4. sql 语句中常用命令
  9. Linux 下使用杀毒软件clamav扫描木马病毒
  10. html加入window播放器,使用 HTML 和 Windows Media Player