文章目录
前言
这是学习springBoot初期的学习笔记。。。欢迎各位大佬指正!!!创建idea集成的springBoot项目
第一步:直接创建就ok,如下:
然后下一步;最终会形成一个这样的目录结构:
在springBoot中使用jsp
第一步添加依赖:
在pom.xml中,如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.drillsb</groupId>
<artifactId>springboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot</name>
<packaging>war</packaging>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
<!-- Servlet的依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!-- tomcat的支持-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/webapp</directory>
<targetPath>META-INF/resources</targetPath>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
</build>
</project>
注意点:
也就是添加三个依赖,如下:
<!-- Servlet的依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!-- tomcat的支持-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
注意了,必须要指明资源的路径,也就是在pom.xml中添加资源的路径,如下:
<!-- 资源路径-->
<resources>
<resource>
<directory>src/main/webapp</directory>
<targetPath>META-INF/resources</targetPath>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
除此之外,跟原来的web项目一样,也要指定资源路径,如下:
然后就形成了,这样的目录结构,如下:
这样就真正的实现了在springboot中使用jsp;
在spring中启动热部署
在pom.xml中添加一个插件和一个依赖即可,如下:
<!-- 添加热部署,其中optional为true才能生效-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
这样在idea中还是实现不了热部署的。。。。因为在idea中默认情况下是不会进行热部署,所以要设置几步;
首先,打开idea的setting设置,然后设置compiler,如下:
然后 Shift+Ctrl+Alt+/,选择Registry,然后如下:
这样就实现热部署了!!!
springboot全局异常处理
参考文章:
spring的@ControllerAdvice注解
SpringMVC 中 @ControllerAdvice 注解的三种使用场景!
关于这个@ControllerAdvice注解;
解释:
@ControllerAdvice注解是Spring3.2中新增的注解,学名是Controller增强器,作用是给Controller控制器添加统一的操作或处理。
写一个类,如下:
package com.drillsb.springboot.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
/**
* 该类是处理异常类
*/
@ControllerAdvice//控制层的增强器
public class GlobalExceptionHandler {
@ExceptionHandler(value = Exception.class)
public ModelAndView defaultErrorHandler(HttpServletRequest request,Exception e){
ModelAndView mav=new ModelAndView();
mav.addObject("exception",e);
mav.addObject("url",request.getRequestURL());
mav.setViewName("errorPage");
return mav;
}
}
然后写一个显示异常的页面errorPage.jsp,如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<div style="width:500px;border:1px solid lightgray;margin:200px auto;padding:80px">
访问该地址出现了异常,异常原因是:<br/>
${exception}
<br/><br/>
出现异常的该地址是:
${url}
</div>
</body>
</html>
然后在随便一个Controller中添加一个异常,如下:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.text.DateFormat;
import java.util.Date;
//@RestController//这个注解的意思:==@ResponseBody和Controller
@Controller
public class HelloController {
@RequestMapping("/hello")
public String hello(Model m){
m.addAttribute("now",
DateFormat.getDateTimeInstance().format(
new Date()));
if(true){
throw new RuntimeException("这个是自定义的异常");
}
return "hello";
}
然后访问,就可以看到实现了处理异常的类信息如下:
application.propertyies的配置
配置端口和上下文路径
在application.properties中配置如下:
server.port=8888 //这个是配置端口
server.context-path=/test //这个是配置访问的上下文路径
其中,以为使用的是1.5版本的springboot,所以配置上下文路径是这样,然后高版本的配置上下文路径,是使用如下:
server.servlet.context-path
反正可以按照提示来,不记得了就看提示的代码如何了;
多配置文件
可以解决在开发和生产环境中使用的端口以及配置等等不一样的问题
在开发中
配置多个文件,如下:
3个配置文件:
核心配置文件:application.properties
开发环境用的配置文件:application-dev.properties
生产环境用的配置文件:application-pro.properties
这样就可以通过application.properties里的spring.profiles.active 灵活地来切换使用哪个环境了
注意了;
其上下文路径配置为 / ,默认就是没有路径的;
核心配置文件中:
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
//使用这个来指定是哪一个环境的配置文件
spring.profiles.active=dev
在开发配置文件application-dev.properties中:
server.port=8080
server.context-path=/
在生成配置文件application-pro.properties中:
server.port=86
server.context-path=/
在项目已经部署中:
不仅可以通过修改application.properties文件进行切换,还可以在部署环境下,指定不同的参数来确保生产环境总是使用的希望的那套配置。
cd C:\Users\X7TI\Downloads\springboot
mvn install
java -jar target/springboot-0.0.1-SNAPSHOT.jar --spring.profiles.active=pro
或者
java -jar target/springboot-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev
语句写的是一样的使用yml
在application.perporties中,可以使用带.yml后缀的文件,其实现的效果是一样的,但是书写格式不太一样,如下为使用yml格式:
spring:
mvc:
view:
prefix: /WEB-INF/jsp/
suffix: .jsp
server:
port: 8080
context-path: /test
注意点
1. 不同“等级” 用冒号隔开 2. 次等级的前面是空格,不能使用制表符(tab) 3. 冒号之后如果有值,那么冒号和值之间至少有一个空格,不能紧贴着4.后缀为.properties和后缀.yml不能同时使用,不是薛定谔的状态,是确定的!!!也就是必须选择一种。
使用jpa
使用idea连接mysql数据库
方式一:注意点: 如图所示,连接好mysql之后,如果需要切换所需要的库,应该点击这个地方:
就是这个 1 of 17,这里是可以点击的!!!!!
方式二:
然后就进入了,这个页面,点击那个schemas,这个单词的意思就是图表:
点击之后也可以切换,如下:
使用jpa规范操作数据库
注意了,这里使用hibernate操作数据库
首先在pom.xml中添加对mysql和jpa的依赖,如下:
<!-- 添加对mysql的支持-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.21</version>
</dependency>
<!-- 添加对jpa的支持-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
然后在application.properties中添加,一系列连接数据库的参数,如下:
注意点:这个编码UTF-8要大写!!!
这个编码UTF-8要大写!!!
这个编码UTF-8要大写!!!
server.port=8080
server.context-path=/
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/sb_test?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
然后创建hibernate的实体类Category,并且使用注解表示hibernate的相关属性,如下:
package com.drillsb.springboot.pojo;
import javax.persistence.*;
@Entity
@Table(name="category_")
public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="id")
private int id;
@Column(name="name")
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
数据库中必须要创建跟实体类对应的表,如下:
CREATE database sb_test
use sb_test
create table sb_people(
id int(11) not null auto_increment,
name varchar(20),
primary key(id)
)default charset=utf8;
insert into sb_people values(null,'p1');
insert into sb_people values(null,'p2');
insert into sb_people values(null,'p3');
insert into sb_people values(null,'p4');
然后按照mvc模式,设计CategoryDAO,
该接口继承了jpa的接口,其中泛型里面一个是对应的实体类,另一个是对应实体类的主键类型
如下:
package com.drillsb.springboot.dao;
import com.drillsb.springboot.pojo.Category;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CategoryDAO extends JpaRepository<Category,Integer> {
}
最后设计Controller,按照常规的spring注解,使用,如下:
package com.drillsb.springboot.web;
import com.drillsb.springboot.dao.CategoryDAO;
import com.drillsb.springboot.pojo.Category;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
@Controller
public class CategoryController {
@Autowired
CategoryDAO categoryDAO;
@RequestMapping("/list")
public String listCategory(Model m){
List<Category> cs = categoryDAO.findAll();
m.addAttribute("cs",cs);
return "listCategory";
}
}
最后就是view层了,设计一个jsp,显示查询category表中的数据,listCategory.jsp如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<table border="1" align="center" cellspacing="0">
<tr>
<td>id</td>
<td>name</td>
</tr>
<c:forEach items="${cs}" var="c" varStatus="st">
<tr>
<td>${c.id}</td>
<td>${c.name}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
最终运行SpringbootApplication类中的主方法,然后访问在Controller中设置的访问路径,如下:
使用jpa规范实现分页增删改查
实体类和依赖,以及使用的框架,都没有变,也就是在上面使用jpa操作数据库的基础上实现crud的;修改Controller,如下:
package com.drillsb.springboot.web;
import com.drillsb.springboot.dao.CategoryDAO;
import com.drillsb.springboot.pojo.Category;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@Controller
public class CategoryController {
@Autowired
CategoryDAO categoryDAO;
/*// 这个是查询该Category表的所有内容
@RequestMapping("/list")
public String listCategory(Model m){
List<Category> cs = categoryDAO.findAll();
m.addAttribute("cs",cs);
return "listCategory";
}*/
@RequestMapping("/listCategory")
public String listCategory(Model m,
@RequestParam(value = "start",defaultValue = "0")int start,
@RequestParam(value = "size",defaultValue = "5")int size){
// 当在首页的时候,再点击上一页的情况下
start=start<0?0:start;
Sort sort = new Sort(Sort.Direction.DESC, "id");
Pageable pb=new PageRequest(start,size,sort);
Page<Category> page = categoryDAO.findAll(pb);
// 遍历当前页面的分页的数据,返回为list数据,这里就是返回Category的集合
System.out.println(page.getContent().toString());
// 获取当前页面数
System.out.println("当前第几页,总是非负的: "+page.getNumber());
System.out.println("返回当前页上的元素数: "+page.getNumberOfElements());
System.out.println("返回当前页面的大小: "+page.getSize());
System.out.println("返回元素总数: "+page.getTotalElements());
// 获取总页面数
System.out.println("返回分页总数: "+page.getTotalPages());
m.addAttribute("page",page);
return "listCategory";
}
/*
* 添加和修改都是使用save,其是根据实体类的id
* 是否为0来判断是进行添加还是修改
* */
// 添加
@RequestMapping("/addCategory")
public String addCategory(Category category){
categoryDAO.save(category);
return "redirect:listCategory";
}
// 删除
@RequestMapping("/deleteCategory")
public String deleteCategory(Category category){
categoryDAO.delete(category);
return "redirect:listCategory";
}
// 修改
@RequestMapping("/updateCategory")
public String updateCategory(Category category){
categoryDAO.save(category);
return "redirect:listCategory";
}
// 通过id获取到某一分类的信息
@RequestMapping("/editCategory")
public String editCategory(int id,Model m){
// 通过id获取到表信息
Category c = categoryDAO.getOne(id);
m.addAttribute("c",c);
return "editCategory";
}
}
其中使用jpa实现分页,使用到了Sort类,Page类,Pageable类,PageRequest类,如下:
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
这四个类都是spring框架的类;
参考文章:
分页工具一Pageable与Page
03:SpringBoot整合SpringDataJPA实现数据库的访问(二)
其中,主要还是Page类,该类实现了Slice类,该类如下:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.data.domain;
import java.util.List;
import org.springframework.core.convert.converter.Converter;
public interface Slice<T> extends Iterable<T> {
int getNumber();
int getSize();
int getNumberOfElements();
List<T> getContent();
boolean hasContent();
Sort getSort();
boolean isFirst();
boolean isLast();
boolean hasNext();
boolean hasPrevious();
Pageable nextPageable();
Pageable previousPageable();
<S> Slice<S> map(Converter<? super T, ? extends S> var1);
}
视图层,listCategory.jsp,如下:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<div align="center">
</div>
<div style="width:500px;margin:20px auto;text-align: center">
<table align='center' border='1' cellspacing='0'>
<tr>
<td>id</td>
<td>name</td>
<td>编辑</td>
<td>删除</td>
</tr>
<c:forEach items="${page.content}" var="c" varStatus="st">
<tr>
<td>${c.id}</td>
<td>${c.name}</td>
<td><a href="editCategory?id=${c.id}">编辑</a></td>
<td><a href="deleteCategory?id=${c.id}">删除</a></td>
</tr>
</c:forEach>
</table>
<br>
<div>
<a href="?start=0">[首 页]</a>
<a href="?start=${page.number-1}">[上一页]</a>
<a href="?start=${page.number+1}">[下一页]</a>
<a href="?start=${page.totalPages-1}">[末 页]</a>
</div>
<br>
<form action="addCategory" method="post">
name: <input name="name"> <br>
<button type="submit">提交</button>
</form>
</div>
上面的代码,值得注意的是,start是当前第几页;并且是从0开始作为开始页,也就是说第一页为0,第二页为1;所以尾页是总页数-1;
editCategory.jsp,如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>editCategory</title>
</head>
<body>
<div style="margin: 0px auto;width:500px ">
<form action="updateCategory" method="post">
<%-- --%>
name:<input name="name" value="${c.name}">
<input name="id" type="hidden" value="${c.id}">
<button type="submit">提交</button>
</form>
</div>
</body>
</html>
启动之后,如下:
使用mybatis
注解方式
在pom.xml中添加mysql和对mybatis的依赖,如下:
<!-- 添加对mysql的支持-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.21</version>
</dependency>
<!-- 添加对jpa的支持-->
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>-->
<!-- 添加对mybatis的支持-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
然后相比于使用hibernate少了许多的配置,配置application.properties文件如下:
server.port=8080
server.context-path=/
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/sb_test?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
然后就是实体类,如下:
注意:
这个实体类必须要跟数据库中的表所对应,不然查找不出数据!!!
这个实体类必须要跟数据库中的表所对应,不然查找不出数据!!!
这个实体类必须要跟数据库中的表所对应,不然查找不出数据!!!
也就是mybatis无法实现映射
package com.drillsb.springboot.pojo;
import javax.persistence.*;
/*@Entity
@Table(name="category_")*/
public class Category {
/* @Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="id")*/
private int id;
/*@Column(name="name")*/
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
之后就是DAO类,在mybatis中是使用Mapper接口来代替,如下:
package com.drillsb.springboot.mapper;
import com.drillsb.springboot.pojo.Category;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
@Mapper
public interface CategoryMapper {
@Select("select * from category_ ")
List<Category> findAll();
}
其Controller类的处理逻辑是跟使用jpa一样的,如下:
package com.drillsb.springboot.web;
import com.drillsb.springboot.mapper.CategoryMapper;
import com.drillsb.springboot.pojo.Category;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
@Controller
public class CategoryControllerMybatis {
@Autowired
CategoryMapper categoryMapper;
@RequestMapping("/listCategory")
public String list(Model m){
List<Category> cs = categoryMapper.findAll();
m.addAttribute("cs",cs);
return "listCategory";
}
}
运行之后,如下:
注解方式实现分页增删改查
分页实现采用了第三方的分页插件;注:xml方式也一样可以实现,只是多了个Mapper类的映射xml的文件而已;
使用了PageHelper分页助手,所以先导依赖包,如下:
<!-- 这个是使用mybatis添加分页助手插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.6</version>
</dependency>
添加依赖之后,分页助手,按照ssm模式的话,也需要在applicationContext.xml文件中添加对分页助手的配置,但是因为是采用注解方式,所以新建一个类,用于代替配置文件,新建一个PageHelperConfig类,如下:
package com.drillsb.springboot.config;
import com.github.pagehelper.PageHelper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
@Configuration//表示该类是一个配置文件类
public class PageHelperConfig {
@Bean
public PageHelper PageHelper(){
PageHelper pageHelper = new PageHelper();
Properties p=new Properties();
p.setProperty("offsetAsPageNum","true");
// rowBoundsWithCount:设置为true时,使用RowBounds分页会进行count查询.
p.setProperty("rowBoundsWithCount","true");
// 启用合理化时,如果pageNum<1会查询第一页,如果pageNum>pages会查询最后一页。
p.setProperty("reasonable","true");
pageHelper.setProperties(p);
return pageHelper;
}
}
这个@Bean这个注解,可参考文章,
SpringBoot中 @Bean 和 @Component的联系区别
除此之外,它是跟@Configuration一起使用的
@Bean不能注释在类上,只能用于在配置类(@Configuration)中显式声明单个bean。意思就是,我要获取这个bean的时候,spring要按照这种方式去获取这个bean。默认情况下@Bean注释的方法名作为对象的名字,也可以用name属性定义对象的名字。
实体类跟前面的一样,保持不变;
然后Mapper类,如下:
package com.drillsb.springboot.mapper;
import com.drillsb.springboot.pojo.Category;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
@Mapper
public interface CategoryMapper {
@Select("select * from category_ ")
public List<Category> findAll();
@Insert("insert into category_(name) values(#{name}) ")
public int save(Category category);
@Delete("delete from category_ where id= #{id} ")
public void delete(int id);
@Select("select * from category_ where id= #{id} ")
public Category get(int id);
@Update("update category_ set name=#{name} where id=#{id} ")
public int update(Category category);
}
值得注意的是,修改是按照数据库表中id去修改的,但是传递给spring的时候,却是数据库对应的实体类的对象
之后就是控制层了,增删改查,如下:
package com.drillsb.springboot.web;
import com.drillsb.springboot.mapper.CategoryMapper;
import com.drillsb.springboot.pojo.Category;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@Controller
public class CategoryControllerMybatis {
@Autowired
CategoryMapper categoryMapper;
@RequestMapping("/list")
public String list(Model m,
@RequestParam(value = "start",defaultValue = "0")int start,
@RequestParam(value = "size",defaultValue = "5") int size){
PageHelper.startPage(start,size,"id desc");
List<Category> cs = categoryMapper.findAll();
PageInfo<Category> pageInfo=new PageInfo<>(cs);
m.addAttribute("page",pageInfo);
return "listCategory";
}
// 增加
@RequestMapping("/addCategory")
public String addCategory(Category c){
categoryMapper.save(c);
return "redirect:listCategory";
}
// 删除
@RequestMapping("/deleteCategory")
public String deleteCategory(int id){
categoryMapper.delete(id);
return "redirect:listCategory";
}
// 修改
@RequestMapping("/updateCategory")
public String updateCategory(Category category){
categoryMapper.update(category);
return "redirect:listCategory";
}
// 编辑
@RequestMapping("/editCategory")
public String editCategory(int id,Model m){
Category c = categoryMapper.get(id);
m.addAttribute("c",c);
return "editCategory";
}
}
然后listCategory.jsp视图层,如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<div style="width: 500px;margin: 20px auto;text-align: center">
<table border="1" align="center" cellspacing="0">
<tr>
<td>id</td>
<td>name</td>
<td>编辑</td>
<td>删除</td>
</tr>
<%-- page.content获取到Category的数据--%>
<c:forEach items="${page.list}" var="c" varStatus="st">
<tr>
<td>${c.id}</td>
<td>${c.name}</td>
<td><a href="editCategory?id=${c.id}">编辑</a></td>
<td><a href="deleteCategory?id=${c.id}">删除</a></td>
</tr>
</c:forEach>
</table>
<br/>
<div>
<a href="?start=0">[首 页]</a>
<a href="?start=${page.pageNum-1}">[上一页]</a>
<a href="?start=${page.pageNum+1}">[下一页]</a>
<a href="?start=${page.pages}">[末 页]</a>
</div>
<br/>
<form action="addCategory" method="post">
name:<input name="name"><br/>
<button type="submit">提交</button>
</form>
</div>
</body>
</html>
其数据的获取跟前面使用jpa不同,使用的是分页助手获取数据的;
editCategory.jsp如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>editCategory</title>
</head>
<body>
<div style="margin: 0px auto;width:500px ">
<form action="updateCategory" method="post">
name:<input name="name" value="${c.name}">
<input name="id" type="hidden" value="${c.id}">
<button type="submit">提交</button>
</form>
</div>
</body>
</html>
启动之后,如下:
xml方式
Controller和实体类不需要改变,只是将Mapper接口的映射方式,改为使用xml文件,Mapper类改为如下:
package com.drillsb.springboot.mapper;
import com.drillsb.springboot.pojo.Category;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
@Mapper
public interface CategoryMapper {
List<Category> findAll();
}
然后在application.properties文件中添加,对Mapper映射文件的地址,以及别名,如下:
server.port=8080
server.context-path=/
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/sb_test?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
mybatis.mapper-locations=classpath:com/drillsb/springboot/mapper/*.xml
mybatis.type-aliases-package=com.drillsb.springboot.pojo
最后其Mapper的配置文件,得在resource目录下,即资源文件目录下,如下图所示:
mybatis.mapper-locations=classpath:com/drillsb/springboot/mapper/*.xml
这个路径名!!!!!因而言,创建该目录的时候,就该如下图所示创建:
而不能用.分隔符创建!!!
其创建的Mapper映射文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.drillsb.springboot.mapper.CategoryMapper">
<select id="findAll" resultType="Category">
select * from category_
</select>
</mapper>
运行还是没有问题的,这样也就完成了跟注解一样的效果!
使用sqlite
这个数据库的详细内容,参考文章如下:
sqlite教程和简介
总而言之,这是一个无须配置的内存数据库;
SQLite是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL
数据库引擎。它是一个零配置的数据库,这意味着与其他数据库不一样,您不需要在系统中配置。
首先在pom.xml添加依赖,如下:
<!-- 添加对sqlite的依赖-->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<scope>runtime</scope>
</dependency>
然后添加三个类,说实话对这三个类一窍不通。。。。如下:
SQLiteDialect类:
package com.drillsb.springboot.sqlite;
import org.hibernate.JDBCException;
import org.hibernate.ScrollMode;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.function.*;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.pagination.AbstractLimitHandler;
import org.hibernate.dialect.pagination.LimitHandler;
import org.hibernate.dialect.pagination.LimitHelper;
import org.hibernate.dialect.unique.DefaultUniqueDelegate;
import org.hibernate.dialect.unique.UniqueDelegate;
import org.hibernate.engine.spi.RowSelection;
import org.hibernate.exception.DataException;
import org.hibernate.exception.JDBCConnectionException;
import org.hibernate.exception.LockAcquisitionException;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.hibernate.internal.util.JdbcExceptionHelper;
import org.hibernate.mapping.Column;
import org.hibernate.type.StandardBasicTypes;
import java.sql.SQLException;
import java.sql.Types;
public class SQLiteDialect extends Dialect {
private final UniqueDelegate uniqueDelegate;
public SQLiteDialect() {
registerColumnType(Types.BIT, "boolean");
registerColumnType(Types.DECIMAL, "decimal");
registerColumnType(Types.CHAR, "char");
registerColumnType(Types.LONGVARCHAR, "longvarchar");
registerColumnType(Types.TIMESTAMP, "datetime");
registerColumnType(Types.BINARY, "blob");
registerColumnType(Types.VARBINARY, "blob");
registerColumnType(Types.LONGVARBINARY, "blob");
registerFunction("concat", new VarArgsSQLFunction(StandardBasicTypes.STRING, "", "||", ""));
registerFunction("mod", new SQLFunctionTemplate(StandardBasicTypes.INTEGER, "?1 % ?2"));
registerFunction("quote", new StandardSQLFunction("quote", StandardBasicTypes.STRING));
registerFunction("random", new NoArgSQLFunction("random", StandardBasicTypes.INTEGER));
registerFunction("round", new StandardSQLFunction("round"));
registerFunction("substr", new StandardSQLFunction("substr", StandardBasicTypes.STRING));
registerFunction("trim", new AbstractAnsiTrimEmulationFunction() {
@Override
protected SQLFunction resolveBothSpaceTrimFunction() {
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "trim(?1)");
}
@Override
protected SQLFunction resolveBothSpaceTrimFromFunction() {
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "trim(?2)");
}
@Override
protected SQLFunction resolveLeadingSpaceTrimFunction() {
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "ltrim(?1)");
}
@Override
protected SQLFunction resolveTrailingSpaceTrimFunction() {
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "rtrim(?1)");
}
@Override
protected SQLFunction resolveBothTrimFunction() {
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "trim(?1, ?2)");
}
@Override
protected SQLFunction resolveLeadingTrimFunction() {
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "ltrim(?1, ?2)");
}
@Override
protected SQLFunction resolveTrailingTrimFunction() {
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "rtrim(?1, ?2)");
}
});
uniqueDelegate = new SQLiteUniqueDelegate(this);
}
private static final SQLiteDialectIdentityColumnSupport IDENTITY_COLUMN_SUPPORT = new
SQLiteDialectIdentityColumnSupport(new SQLiteDialect());
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return IDENTITY_COLUMN_SUPPORT;
}
// limit/offset support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private static final AbstractLimitHandler LIMIT_HANDLER = new AbstractLimitHandler() {
@Override
public String processSql(String sql, RowSelection selection) {
final boolean hasOffset = LimitHelper.hasFirstRow(selection);
return sql + (hasOffset ? " limit ? offset ?" : " limit ?");
}
@Override
public boolean supportsLimit() {
return true;
}
@Override
public boolean bindLimitParametersInReverseOrder() {
return true;
}
};
@Override
public LimitHandler getLimitHandler() {
return LIMIT_HANDLER;
}
// lock acquisition support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean supportsLockTimeouts() {
// may be http://sqlite.org/c3ref/db_mutex.html ?
return false;
}
@Override
public String getForUpdateString() {
return "";
}
@Override
public boolean supportsOuterJoinForUpdate() {
return false;
}
// current timestamp support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean supportsCurrentTimestampSelection() {
return true;
}
@Override
public boolean isCurrentTimestampSelectStringCallable() {
return false;
}
@Override
public String getCurrentTimestampSelectString() {
return "select current_timestamp";
}
// SQLException support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private static final int SQLITE_BUSY = 5;
private static final int SQLITE_LOCKED = 6;
private static final int SQLITE_IOERR = 10;
private static final int SQLITE_CORRUPT = 11;
private static final int SQLITE_NOTFOUND = 12;
private static final int SQLITE_FULL = 13;
private static final int SQLITE_CANTOPEN = 14;
private static final int SQLITE_PROTOCOL = 15;
private static final int SQLITE_TOOBIG = 18;
private static final int SQLITE_CONSTRAINT = 19;
private static final int SQLITE_MISMATCH = 20;
private static final int SQLITE_NOTADB = 26;
@Override
public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
return new SQLExceptionConversionDelegate() {
@Override
public JDBCException convert(SQLException sqlException, String message, String sql) {
final int errorCode = JdbcExceptionHelper.extractErrorCode(sqlException) & 0xFF;
if (errorCode == SQLITE_TOOBIG || errorCode == SQLITE_MISMATCH) {
return new DataException(message, sqlException, sql);
} else if (errorCode == SQLITE_BUSY || errorCode == SQLITE_LOCKED) {
return new LockAcquisitionException(message, sqlException, sql);
} else if ((errorCode >= SQLITE_IOERR && errorCode <= SQLITE_PROTOCOL) || errorCode == SQLITE_NOTADB) {
return new JDBCConnectionException(message, sqlException, sql);
}
// returning null allows other delegates to operate
return null;
}
};
}
@Override
public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() {
return EXTRACTER;
}
private static final ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() {
@Override
protected String doExtractConstraintName(SQLException sqle) throws NumberFormatException {
final int errorCode = JdbcExceptionHelper.extractErrorCode(sqle) & 0xFF;
if (errorCode == SQLITE_CONSTRAINT) {
return extractUsingTemplate("constraint ", " failed", sqle.getMessage());
}
return null;
}
};
// union subclass support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean supportsUnionAll() {
return true;
}
// DDL support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean canCreateSchema() {
return false;
}
@Override
public boolean hasAlterTable() {
// As specified in NHibernate dialect
return false;
}
@Override
public boolean dropConstraints() {
return false;
}
@Override
public boolean qualifyIndexName() {
return false;
}
@Override
public String getAddColumnString() {
return "add column";
}
@Override
public String getDropForeignKeyString() {
throw new UnsupportedOperationException("No drop foreign key syntax supported by SQLiteDialect");
}
@Override
public String getAddForeignKeyConstraintString(String constraintName,
String[] foreignKey, String referencedTable, String[] primaryKey,
boolean referencesPrimaryKey) {
throw new UnsupportedOperationException("No add foreign key syntax supported by SQLiteDialect");
}
@Override
public String getAddPrimaryKeyConstraintString(String constraintName) {
throw new UnsupportedOperationException("No add primary key syntax supported by SQLiteDialect");
}
@Override
public boolean supportsCommentOn() {
return true;
}
@Override
public boolean supportsIfExistsBeforeTableName() {
return true;
}
@Override
public boolean doesReadCommittedCauseWritersToBlockReaders() {
// TODO Validate (WAL mode...)
return true;
}
@Override
public boolean doesRepeatableReadCauseReadersToBlockWriters() {
return true;
}
@Override
public boolean supportsTupleDistinctCounts() {
return false;
}
@Override
public int getInExpressionCountLimit() {
return 1000;
}
@Override
public UniqueDelegate getUniqueDelegate() {
return uniqueDelegate;
}
private static class SQLiteUniqueDelegate extends DefaultUniqueDelegate {
public SQLiteUniqueDelegate(Dialect dialect) {
super(dialect);
}
@Override
public String getColumnDefinitionUniquenessFragment(Column column) {
return " unique";
}
}
@Override
public String getSelectGUIDString() {
return "select hex(randomblob(16))";
}
@Override
public ScrollMode defaultScrollMode() {
return ScrollMode.FORWARD_ONLY;
}
}
SQLiteDialectIdentityColumnSupport类
package com.drillsb.springboot.sqlite;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.identity.IdentityColumnSupportImpl;
public class SQLiteDialectIdentityColumnSupport extends IdentityColumnSupportImpl {
public SQLiteDialectIdentityColumnSupport(Dialect dialect) {
super(dialect);
}
@Override
public boolean supportsIdentityColumns() {
return true;
}
@Override
public boolean hasDataTypeInIdentityColumn() {
return false;
}
@Override
public String getIdentitySelectString(String table, String column, int type) {
return "select last_insert_rowid()";
}
@Override
public String getIdentityColumnString(int type) {
return "integer";
}
}
SQLiteMetadataBuilderInitializer类
package com.drillsb.springboot.sqlite;
import org.hibernate.boot.MetadataBuilder;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.spi.MetadataBuilderInitializer;
import org.hibernate.engine.jdbc.dialect.internal.DialectResolverSet;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolver;
import org.jboss.logging.Logger;
public class SQLiteMetadataBuilderInitializer implements MetadataBuilderInitializer {
private final static Logger logger = Logger.getLogger(SQLiteMetadataBuilderInitializer.class);
@Override
public void contribute(MetadataBuilder metadataBuilder, StandardServiceRegistry serviceRegistry) {
DialectResolver dialectResolver = serviceRegistry.getService(DialectResolver.class);
if (!(dialectResolver instanceof DialectResolverSet)) {
logger.warnf("DialectResolver '%s' is not an instance of DialectResolverSet, not registering SQLiteDialect",
dialectResolver);
return;
}
((DialectResolverSet) dialectResolver).addResolver(resolver);
}
static private final SQLiteDialect dialect = new SQLiteDialect();
static private final DialectResolver resolver = (DialectResolver) info -> {
if (info.getDatabaseName().equals("SQLite")) {
return dialect;
}
return null;
};
}
然后就是在application.properties中添加对sqlite数据库的支持,如下:
#这个是对sqlite的配置
spring.jpa.database-platform=com.drillsb.springboot.sqlite.SQLiteDialect
#表结构由hibernate根据实体类来创建
spring.jpa.generate-ddl=true
#自动根据pojo配置创建表
spring.jpa.hibernate.ddl-auto=update
#数据库文件位置
spring.datasource.url=jdbc:sqlite:example.db
#驱动名称
spring.datasource.tomcat.driver-class-name=org.sqlite.JDBC
因为只是对持久层改变,所以其他的不用修改;之后重启,然后访问地址之后是一篇空白的。。。因为还没有数据,所以需要自己一点一点的添加数据进去,添加之后访问如下: