华清远见-重庆中心-框架技术总结
框架是一套规范。
实际是他人实现的一系列接口和类的集合。通过导入对应框架的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);
华清远见-重庆中心-框架技术总结相关推荐
- 华清远见-重庆中心-框架阶段技术总结/知识点梳理
文章目录 华清远见-重庆中心-框架阶段技术总结/知识点梳理/个人总结 框架 Java主流框架 Spring 概念 组成 名词解释 IOC DI Spring控制台应用 1.创建一个普通的Maven项目 ...
- 华清远见-重庆中心-框架阶段技术总结
框架 一套规范. 实际是他人实现的一系列接口和类的集合.通入导入对应框架的jar文件(maven项目导入对应的依赖),进行适当的配置,就能使用其中的所有内容. 开发者可以省去很多模板代码,如dao中的 ...
- 华清远见-重庆中心-框架部分技术总结
目录 框架 Java主流框架 Spring 概念 组成 名词解释 IOC DI AOP Spring控制台应用 1.创建一个普通的Maven项目,不选择模板 2.添加Spring核心依赖 3.创建一个 ...
- 华清远见-重庆中心-前端技术总结/知识点梳理/个人总结/面试题解析
HTML 1.1什么是HTML 超文本:有视频,音频,图片等,超越文本 超文本标记语言(Hyper Text Markup Language) 标记语言:有一套标签 1.2标签 是由<>包 ...
- 华清远见-重庆中心-前端技术阶段
花了两周多的时间对HTML.CSS.JavaScript和jQuery进行系统性的学习,学习完了后打算花一点时间对之前学习的内容进行复习巩固与总结,划分熟悉程度进行不同程度的梳理,顺便记录. 复习 H ...
- 华清远见-重庆中心-框架个人总结
框架 一套规范. 实际是他人实现的一系列接口和类的集合.通入导入对应框架的jar文件(maven项目导入对应的依赖),进行适当的配置,就能使用其中的所有内容. 开发者可以省去很多模板代码,如dao中的 ...
- 华清远见重庆中心—JavaWeb技术总结/个人总结
JavaWeb 网站 用户通过浏览器访问某个域名或ip后,浏览到的综合性页面. 实际是发布在服务器上的一个应用程序,通过浏览器访问. 网页 网站中的某张页面 静态页面:所有人看到的内容都一样 动态页面 ...
- 华清远见重庆中心-面向对象技术总结/个人总结
Java中标识符的命名规则 标识符 类名.方法名.变量名统称为标识符 标识符命名规范 帕斯卡命名法 所有单词首字母大写 如Employee.ClassName.StudentInfomation 驼峰 ...
- 华清远见-重庆中心-JavaWeb技术总结
JavaWeb 使用Java开发Web服务的技术,统称为JavaWeb. B/S与C/S模式 B/S:Browser/Server 浏览器/服务器模式 用户只需要一个浏览器即可访问服务器 C/S:Cl ...
最新文章
- 60日均线操盘的三种入场点形态
- python语言需要英语非常好吗-Python用不好英语水平不够?这里有官方中文文档你看不看...
- dedecms织梦修改标题默认长度
- 9、MySQL系统变量(查看和修改)
- java编程笔记18 文件压缩与解压缩
- zookeeper zoo.cfg配置文件
- 小程序开发(6)-之自定义导航栏
- 我看中国软件---规模篇
- Qt文档阅读笔记-官方2D Painting Example实例解析
- html(7)盒子模型
- postgresql获取表最后更新时间(通过触发器将时间写入另外一张表)
- 什么是 “动态规划” , 用两个经典问题举例。
- 「thunar」给thunar增加搜索文件功能
- LINUX中错误 SELinux is disabled
- 在Android开发中如何移除EditText上的输入焦点
- 光波波长划分和无线电波频段划分
- 64位java没有javaw.exe_javaw.exe路径错误导致eclipse无法启动
- 再见了,我的黄色文件夹(内置福利)
- 一文带你深入了解,什么是深度学习及其工作原理
- 女星长发如雪 上演现代版白发魔女传(组图)
热门文章
- 计算机电源用什么端子,三菱PLC电源端子的接线方法图解
- AI智能阅读助力全栈开发-逐浪CMS语音辅助2.0发布
- [附源码]计算机毕业设计JAVA保险业务管理系统
- kicad 自动生成封装库_【工具】KiCad版本嘉立创SMT贴片库及问题说明
- 文献阅读笔记整理--ConvNext:A ConvNet for the 2020s
- 使用Arduino Leonardo开发板制作操纵杆游戏控制器
- VisionMaster标定板标定
- 4. sql 语句中常用命令
- Linux 下使用杀毒软件clamav扫描木马病毒
- html加入window播放器,使用 HTML 和 Windows Media Player