SpringBoot的web开发
1 SpringBoot的web开发
2 静态资源映射
项目中有许多的静态资源,比如css,js等文件, Spring Boot 项目是以 JAR 包的形式进行部署的,不存在 webapp 目录,那么SpringBoot怎么处理呢?
Spring Boot 默认为我们提供了 3 种静态资源映射规则:
- WebJars 映射
- 默认资源映射
- 静态首页(欢迎页)映射
Webjars 映射
Webjars本质就是以jar包的方式引入我们的静态资源 , 我们以前要导入一个静态资源文件,直接导入即可。
要使用jQuery,我们只要要引入jQuery对应版本的pom依赖即可!(https://www.webjars.org )
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.4.1</version>
</dependency>
所有通过 WebJars 引入的前端资源都存放在当前项目类路径(classpath)下的“/META-INF/resources/webjars/” 目录中。
默认静态资源映射
项目中使用自己的静态资源该怎么导入呢?
以下四个目录存放的静态资源可以被我们识别:
"classpath:/META-INF/resources/"
"classpath:/resources/"
"classpath:/static/"
"classpath:/public/"
我们可以在resources根目录下新建对应的文件夹,都可以存放我们的静态文件;
比如我们访问 http://localhost:8080/1.js , 他就会去这些文件夹中寻找对应的静态资源文件;
自定义静态资源路径
在application.properties中配置。一旦自己定义了静态文件夹的路径,原来的自动配置就都会失效了!
3 Thymeleaf模板引擎
SpringBoot项目首先是以jar的方式,不是war,用的还是嵌入式的Tomcat,所以他现在默认是不支持jsp的。
模板引擎的作用就是我们来写一个页面模板,比如有些值呢,是动态的,我们写一些表达式。而这些值,从哪来呢,就是我们在后台封装一些数据。
然后把这个模板和这个数据交给我们模板引擎,模板引擎按照我们这个数据帮你把这表达式解析、填充到我们指定的位置,然后把这个数据最终生成一个我们想要的内容给我们写出去,这就是我们这个模板引擎,不管是jsp还是其他模板引擎,都是这个思想。
4 SpringMVC自动配置
Spring Boot 抛弃了传统 xml 配置文件,通过配置类(标注 @Configuration 的类,相当于一个 xml 配置文件)以 JavaBean 形式进行相关配置。
Spring Boot 对 Spring MVC 的自动配置可以满足我们的大部分需求,但是我们也可以通过自定义配置类(标注 @Configuration 的类)并实现 WebMvcConfigurer
接口来定制 Spring MVC 配置,例如拦截器、格式化程序、视图控制器等等。
5 WebMvcConfigurer接口详解
1 什么是WebMvcConfigurer
WebMvcConfigurer配置类其实是Spring
内部的一种配置方式,采用JavaBean
的形式来代替传统的xml
配置文件形式进行针对框架个性化定制,可以自定义一些Handler,Interceptor,ViewResolver,MessageConverter。
基于java-based方式的spring mvc配置,需要创建一个配置类(@Configuration)并实现WebMvcConfigurer
接口;
举例:
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
/* 视图跳转控制器 */
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/index.html").setViewName("index");
}
}
2 WebMvcConfigurer接口常用的方法
/* 拦截器配置 */
void addInterceptors(InterceptorRegistry var1);
/* 视图跳转控制器 */
void addViewControllers(ViewControllerRegistry registry);
/**
*静态资源处理
**/
void addResourceHandlers(ResourceHandlerRegistry registry);
/* 默认静态资源处理器 */
void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer);
/**
*这里配置视图解析器
**/
void configureViewResolvers(ViewResolverRegistry registry);
/* 配置内容裁决的一些选项*/
void configureContentNegotiation(ContentNegotiationConfigurer configurer);
/** 解决跨域问题 **/
public void addCorsMappings(CorsRegistry registry) ;
详解(作者:xiari1991):https://www.jianshu.com/p/23afaf36cfa1
3 addViewControllers视图跳转控制器
以前写SpringMVC的时候,如果需要访问一个页面,必须要写Controller类,然后再写一个方法跳转到页面,感觉好麻烦。
其实重写WebMvcConfigurer中的addViewControllers方法即可达到效果了
4 addInterceptors拦截器
addInterceptor:需要一个实现HandlerInterceptor
接口的拦截器实例
addPathPatterns:用于设置拦截器的过滤路径规则;addPathPatterns("/**")
对所有请求都拦截
excludePathPatterns:用于设置不需要拦截的过滤规则
拦截器主要用途:进行用户登录状态的拦截,日志的拦截等。
用户登录状态的拦截
//登录拦截
public class LoginHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//用request.getSession().getAttribute(key)获取的session值
Object loginUser = request.getSession().getAttribute("loginUser");
if(loginUser == null){ //未登录
request.setAttribute("msg","没有权限");
//getRequestDispatcher()包含两个重要方法,分别是请求转发和请求包含
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}else
return true;
}
}
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
/* 登录拦截器配置 */
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginHandlerInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/index.html", "/", "/user/login", "/asserts/**");
}
}
6 JDBC访问数据库
对于数据访问层,无论是 SQL(关系型数据库) 还是 NOSQL(非关系型数据库),Spring Boot 底层都是采用 Spring Data 的方式进行统一处理。
1 导入 JDBC 场景启动器、数据库驱动
在 pom.xml 中导入 JDBC 场景启动器:spring-boot-starter-data-jdbc
、 MySQL 的数据库驱动:mysql-connector-java
2 编写yaml配置文件连接数据库
spring:
thymeleaf:
cache: false
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 12345
url: jdbc:mysql://localhost:3306/springbootweb?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC
3 测试能否连接成功
@SpringBootTest
class Springboot04DataApplicationTests {
@Resource
DataSource dataSource;
@Test
public void contextLoads() throws SQLException {
System.out.println(dataSource.getClass());
Connection connection = dataSource.getConnection();
System.out.println(connection);
//关闭
connection.close();
}
////////////////////////
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
public void getAll(){
String sql = "select * from department";
/没有实体类,怎么获取数据库的数据?万能的map
List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
System.out.println(maps);
}
}
运行结果:可以看到默认配置的数据源为 : class com.zaxxer.hikari.HikariDataSource
, 我们并没有手动配置。HikariDataSource
号称 Java WEB 当前速度最快的数据源,相比于传统的 C3P0 、DBCP、Tomcat jdbc
等连接池更加优秀;
JDBCTemplate
1、有了数据源(com.zaxxer.hikari.HikariDataSource),然后可以拿到数据库连接(java.sql.Connection),有了连接,就可以使用原生的 JDBC 语句来操作数据库;
2、即使不使用第三方第数据库操作框架,如 MyBatis等,Spring 本身也对原生的JDBC 做了轻量级的封装,即JdbcTemplate。
3、数据库操作的所有 CRUD 方法都在 JdbcTemplate 中。
4、Spring Boot 不仅提供了默认的数据源,同时默认已经配置好了 JdbcTemplate 放在了容器中,程序员只需自己注入即可使用
5、JdbcTemplate 的自动配置是依赖org.springframework.boot.autoconfigure.jdbc
包下的 JdbcTemplateConfiguration
类
JdbcTemplate主要提供以下几类方法:
- execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
- update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;
- query方法及queryForXXX方法:用于执行查询相关语句;
- call方法:用于执行存储过程、函数相关语句。
/**
* @Controller 将当前修饰的类注入SpringBoot IOC容器,
* 使得从该类所在的项目跑起来的过程中, 这个类就被实例化。
*
* @ResponseBody 它的作用简短截说就是指该类中所有的API接口返回的数据,
* 甭管你对应的方法返回Map或是其他Object,它会以Json字符串的形式返回给客户端,
* 本人尝试了一下,如果返回的是String类型,则仍然是String。
*/
@RestController
public class JDBCController {
@Autowired
JdbcTemplate jdbcTemplate;
//没有实体类,怎么获取数据库的数据?万能map
//查询
@GetMapping("/list")
public List<Map<String,Object>> userList(){
String sql = "select * from department";
List<Map<String, Object>> list_maps = jdbcTemplate.queryForList(sql);
//System.out.println(list_maps);
return list_maps;
}
//增加
@GetMapping("/add")
public String addUser(){
String sql = "insert into department(id,dname) values(106,'垃圾部')";
jdbcTemplate.update(sql); //自动提交事务
return "add_okok";
}
//修改
@GetMapping("/update/{id}")
public String update(@PathVariable("id")int id){
String sql = "update department set dname=? where id="+id;
//封装
Object o = new Object();
o = "超级垃圾部";
jdbcTemplate.update(sql,o);
return "update_ok";
}
//删除
@GetMapping("/delete/{id}")
public String delete(@PathVariable("id")int id){
String sql = "delete from department where id=?";
jdbcTemplate.update(sql,id);
return "delete_okok";
}
}
7 整合Druid数据源
http://c.biancheng.net/spring_boot/druid.html
8 整合MyBatis
1、导入 MyBatis 所需要的依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
2、配置数据库连接信息
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 12345
url: jdbc:mysql://localhost:3306/springbootweb?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC
#整合mybatis,重要重要
mybatis:
# 配置XML映射文件中指定的实体类别名路径
type-aliases-package: com.yu.pojo
# 配置MyBatis的xml配置文件路径
mapper-locations: classpath:mybatis/mapper/*.xml #映射路径
# 开启驼峰uName自动映射到u_name
# map-underscore-to-camel-case: true
3、测试数据库是否连接成功
@Autowired
DataSource dataSource;
@Autowired
JdbcTemplate jdbcTemplate;
@Test
void contextLoads() throws SQLException {
System.out.println(dataSource.getClass());
System.out.println(dataSource.getConnection());
String sql = "select * from department";
List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);
System.out.println(maps);
}
4、创建实体类(实体类的属性名和数据库列名不一致时)
{"id":105,"departmentName":null} //字段名不对应时为null
解决办法:使用resultMap
<mapper namespace="com.yu.DeptDao">
<resultMap id="deptResultMap" type="User">
<!--
主键字段
property: 实体类属性名.
column: 库中表的列名
javaType: 数据类型.
-->
<id property="userId" column="id" javaType="int"></id>
<!-- 非主键字段 -->
<result property="userSex" column="sex" javaType="string"></result>
<result property="userAddress" column="address" javaType="string"></result>
<result property="userBirthday" column="birthday" javaType="date"></result>
<result property="username" column="username" javaType="string"></result>
</resultMap>
<select id="queryAll" resultMap="deptResultMap">
select * from user
</select>
</mapper>
5、创建mapper目录以及对应的 Mapper 接口
com.yu.mapper.DepartmentMapper.java
接口
//把mapper这个dao==mapper交給Spring管理 ,不用再写mapper映射xml文件,
//自动根据这个添加@Mapper注解的接口生成一个实现类
@Mapper
@Repository
public interface DeptMapper {
//查询所有
List<Department> queryDeptList();
//查一个
Department queryDeptById(int id);
//增改删
int addDept(Department department);
int updateDept(int id);
int deleteDept(int id);
}
补充:某些实体类之间肯定有关键关系,比如一对一,一对多等。在mybatis 中用association
和collection
association: 一对一关联(has one)
collection: 一对多关联(has many)
只有在做select查询时才会用到这两个标签,都有三种用法,且用法类似。
<resultMap id="EmployeeMap" type="Employee">
<!-- 主键 -->
<id property="id" column="eid"/>
<!-- 非主键 -->
<result property="lastName" column="last_name"/>
<result property="email" column="email"/>
<result property="gender" column="gender"/>
<result property="birth" column="birth"/>
<association property="eDepartment" javaType="Department">
<id property="id" column="did"/>
<result property="departmentName" column="dname"/>
</association>
</resultMap>
6、对应的Mapper映射文件
resourses/mybatis/mapper/DepartmentMapper.xml
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yu.mapper.DeptMapper">
<select id="queryDeptList" resultType="Department">
select * from department
</select>
<select id="queryDeptById" resultType="Department">
select * from department where id=#{id}
</select>
<insert id="addDept" parameterType="Department">
insert into department(id,dname) values (#{id},#{dname})
</insert>
<update id="updateDept" parameterType="Department">
update department set id=#{id},dname=#{dname} where id=#{id}
</update>
<delete id="deleteDept" parameterType="int">
delete from department where id=#{id}
</delete>
</mapper>
7、maven配置资源过滤问题
8、测试
@RestController
public class DeptController {
@Autowired
private DeptMapper deptMapper;
@GetMapping("/list")
public List<Department> queryDeptList(){
List<Department> departments = deptMapper.queryDeptList();
//System.out.println(departments);
return departments;
}
}