引出
1.mybatis可以实现SQL语句和Java代码的解耦;
2.mybatis使用,tomcat的war包,和spring的jar包,分页的拦截器;
3.mybatis项目应用初步,SqlSessionUtils工具类,泛型的方式;
4.多条件查询<where,choose,when,otherwise,foreach,if>,排序order;
5.事务回滚,要么都成功,要么都失败,@Transactional注解;
6.在tomcat和spring框架下,常见的报错集锦
mybatis框架使用
https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api
1.导包:mybatis包+分页的包pom.xml文件【war包】
mybatis的包,日志相关的包,分页相关的包,
<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 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.tianju</groupId>
<artifactId>javawebHome0529</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- jsp相关-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>1.1.2</version>
</dependency>
<!-- 数据库相关-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.22.RELEASE</version>
</dependency>
<!-- 其他-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<!-- 工具包-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.11</version>
</dependency>
<!-- fastjson包-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<!-- mybatis 框架-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!-- 分页相关的包-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.5</version>
</dependency>
<!-- 日志相关的包-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
1.导包:mybatis包+分页的包pom.xml文件【jar包】
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>communityManager</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 项目打包成jar包-->
<packaging>jar</packaging>
<!-- 项目描述-->
<description>物业管理v1.0版本</description>
<!-- 继承一个父-->
<parent>
<groupId>org.springframework.boot</groupId>
<version>2.3.0.RELEASE</version>
<artifactId>spring-boot-starter-parent</artifactId>
</parent>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!-- 做web项目的包-->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 前端模板引擎,功能类似于jsp-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 分页工具,匹配springBoot的jar包-->
<!-- 后面加spring-boot-starter,表示按照spring重新改写的版本-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.12</version>
</dependency>
<!-- mybatis的包-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<!-- druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 工具包-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.11</version>
</dependency>
<!-- commons-io-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.2</version>
</dependency>
<!-- 阿里云短信验证码相关包-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-core</artifactId>
<version>4.5.3</version>
</dependency>
<!-- fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<!-- 增强方法的包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<!-- 测试sql mapper 的包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
<!-- 构建-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml配置文件
server:
port: 82
# 1.连接数据库——对应之前 xml文件的数据库
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/community?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: 123
## TODO:设置上传文件大小
servlet:
multipart:
max-file-size: 10MB # 设置单个文件最大大小为10MB
# mybatis其他配置
mybatis:
# 2.给实体类起别名,首字母小写
type-aliases-package: com.tianju.entity
configuration:
# 3.开启驼峰命名
map-underscore-to-camel-case: true
# 4.让日志生效
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 5.扫描sql的位置
mapper-locations: classpath:/mapper/*Mapper.xml
# 全局的一个路径,用@Values获取
repairImg: D:/620/repair/
# 日志的相关配置
logging:
file:
name: D:\\620\\log\\community.log
level:
org.springframework.web: debug
com.tianju: debug
org.springframework.jdbc.support.JdbcTransactionManager: debug
2.resources下配置mybatis-config.xml文件,以及log4j.properties文件
my-batis-cofig.xml
要点:
(1)开启驼峰命名;(2)日志生效;(3)给所有实体类起别名;(4)分页工具PageHelper要加拦截器;(5)配置连接数据库相关的driver,url,username,password;其中url需要在&后面加 amp;
(6)配置mapper,采用简化的方式,用<package,点的方式
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 数据库和实体类 驼峰的问题 :开启驼峰命名-->
<settings>
<!-- 处理驼峰命名-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 日志生效-->
<setting name="logImpl" value="LOG4J"/>
</settings>
<!-- 别名 给所有的实体类都起一个别名com.tianju.entity,所有别名都是类名的首字母小写-->
<typeAliases>
<package name="com.tianju.entity"/>
</typeAliases>
<!-- 分页需要加个拦截器-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql"/>
</plugin>
</plugins>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</dataSource>
</environment>
</environments>
<!-- 告诉配置文件,sql的xml文件在哪,java找用. 普通文件用 /-->
<mappers>
<!-- 简化方式,不然得写很多mapper-->
<!-- <mapper resource="com/tianju/dao/UserMapper.xml"/>-->
<package name="com.tianju.dao"/>
</mappers>
</configuration>
log4j.properties文件:
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
#log4j.rootCategory=debug, CONSOLE, LOGFILE
log4j.rootCategory=debug, CONSOLE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=D:/axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
3.在resources下建文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 指定xml文件和 项目中哪个接口对应-->
<mapper namespace="com.tianju.dao.ComUserMapper">
</mapper>
4.在UserMapper中写SQL
要点:
(1)update,delete,insert不要写成select,不然会出现删除数据后,数据库确实删除了,但是前端list还有;
(2)if语句中不要忘记加逗号:
(3)select语句中,要记得加返回值;
mybatis项目应用
1.封装SqlSessionUtils.java工具类
要点:
- 读取mybatis配置文件,告诉那里读取;
- 生成一个建造sqlSession工厂的建造者,SqlSessionFactoryBuilder;
- 建造者SqlSessionFactoryBuilder根据mybatis-config.xml建造一个SqlSession工厂,SqlSessionFactory;
- 在SqlSession工厂中,通过SqlSessionFactory生成一个sqlSession,且打开自动提交sqlSession = sqlSessionFactory.openSession(true);
- 需要什么类型的mapper就提供什么类型的mapper,public static <T> T getMapper(Class<T> mapperClass){return sqlSession.getMapper(mapperClass);};
getMapper方法—泛型T
package com.tianju.util;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class SqlSessionUtils {
private static SqlSession sqlSession;
static {
//1.读取mybatis配置文件
InputStream is = null;
try {
is = Resources.getResourceAsStream("mybatis-config.xml");
} catch (IOException e) {
throw new RuntimeException(e);
}
//2.生成一个工厂--这个工程是通过建造者建造出来的
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//3.建造者根据mybatis-config.xml建造一个SqlSession工厂
SqlSessionFactory sqlSessionFactory = builder.build(is);
//4.通过sqlSessionFactory生成一个sqlSession
sqlSession = sqlSessionFactory.openSession(true);
//如果设置为true,每次自动提交
}
public static <T> T getMapper(Class<T> mapperClass){
return sqlSession.getMapper(mapperClass);
}
}
2.多条件查询<where, if>,传入Boolean
@Mapper
public interface HouseMapper {
List<House> queryList(
@Param("buildingId") Integer buildingId, // 楼栋
@Param("storey") Integer storey, // 楼层
@Param("roomNum") String roomNum, // 房间号
@Param("areaMin") Double areaMin, // 面积
@Param("areaMax") Double areaMax, // 面积
@Param("intoDateBegin") Date intoDateBegin, // 入住开始时间
@Param("intoDateEnd") Date intoDateEnd, // 入住结束时间
@Param("areaOrderASC") Boolean areaOrderASC,
@Param("areaOrderDESC") Boolean areaOrderDESC// 排序
);
<mapper namespace="com.tianju.dao.HouseMapper">
<select id="queryList" resultType="house">
<!-- SELECT-->
<!-- c_owner_house.*,-->
SELECT
c_house.id,
c_owner_house.ownerId,
c_building.num,c_building.floors,c_building.unit,
c_house.storey,c_house.roomNum,c_house.area,c_house.into_date,c_house.status,c_house.building_id,
user_owner.realname AS ownerName
FROM c_house
LEFT JOIN c_building ON c_building.id = c_house.building_id
LEFT JOIN c_owner_house ON c_owner_house.houseId = c_house.id
LEFT JOIN user_owner ON user_owner.id = c_owner_house.ownerId
<where>
<if test="buildingId!=null">
c_building.id=#{buildingId}
</if>
<if test="storey!=null">
AND c_house.storey=#{storey}
</if>
<if test="areaMin!=null">
AND c_house.area >= #{areaMin}
</if>
<if test="areaMax!=null">
AND c_house.area <= #{areaMax}
</if>
<if test="intoDateBegin!=null">
AND c_house.into_date > #{intoDateBegin}
</if>
<if test="intoDateEnd!=null">
AND c_house.into_date <= #{intoDateEnd}
</if>
<if test="roomNum!=null and roomNum!=''">
AND roomNum LIKE #{roomNum}
</if>
</where>
<if test="areaOrderASC">
ORDER BY c_house.area
</if>
<if test="areaOrderDESC">
ORDER BY c_house.area DESC
</if>
</select>
service层使用
@Autowired
private HouseMapper houseMapper;
@Override
public PageInfo<House> queryList(Integer buildingId, Integer storey, String roomNum, Double areaMin, Double areaMax, Date intoDateBegin, Date intoDateEnd,
Integer pageNum, Integer pageSize,
Boolean areaOrderASC, Boolean areaOrderDESC) {
PageHelper.startPage(pageNum,pageSize);
List<House> list = houseMapper.queryList(buildingId,storey,roomNum,areaMin,areaMax,intoDateBegin,intoDateEnd,areaOrderASC,areaOrderDESC);
return new PageInfo<>(list);
}
3.多条件查询IN,foreach+可变长度参数<choose,when,otherwise>,传入list
/**
* 查询空闲的房子,根据buildingId查询,忽略单元
* @param buildingIdList 根据buildingId查询房间,默认查询空间房间,如果status为false,
* 则也可以查询到非空闲的房间
* @param status 默认为true,如果为false,则可以查询到非空闲房子
* @return
*/
List<House> queryHouseByBuildingId(
@Param("buildingIdList") List<Integer> buildingIdList,
@Param("status") Boolean... status);
<select id="queryHouseByBuildingId" resultType="house">
<!-- SELECT * FROM c_house WHERE building_id IN (1,2,3) AND !status-->
SELECT * FROM c_house
WHERE
building_id IN
<foreach collection="buildingIdList" open="(" separator="," close=")" item="id">
#{id}
</foreach>
<choose>
<when test="status!=null and status.length>0 and !status[0]">
<!-- 如果为false,则可以查询到非空闲房子-->
</when>
<otherwise>
AND !status
</otherwise>
</choose>
</select>
4.多条件查询进阶版<where,choose,when,otherwise,foreach,if>
/**
* 查询所有空闲的房子,显示到左边的框里面 TODO:后面再全查询的基础上进行
*/
List<House> queryAllNoIntoHouse(
@Param("buildingIdList") List<Integer> buildingIdList, // 楼栋
@Param("storey") Integer storey, // 楼层
@Param("areaMin") Double areaMin, // 面积
@Param("areaMax") Double areaMax, // 面积
@Param("areaOrderASC") Boolean areaOrderASC,
@Param("areaOrderDESC") Boolean areaOrderDESC,// 排序
@Param("status") Boolean... status // 如果为false,则可以查询到非空闲房子,其他情况 都是查询空闲房子
);
<select id="queryAllNoIntoHouse" resultType="house">
SELECT
c_house.id,
c_owner_house.ownerId,
c_building.num,c_building.floors,c_building.unit,
c_house.storey,c_house.roomNum,c_house.area,c_house.into_date,c_house.status,c_house.building_id,
user_owner.realname AS ownerName
FROM c_house
LEFT JOIN c_building ON c_building.id = c_house.building_id
LEFT JOIN c_owner_house ON c_owner_house.houseId = c_house.id
LEFT JOIN user_owner ON user_owner.id = c_owner_house.ownerId
<where>
<choose>
<when test="buildingIdList!=null and buildingIdList.size()>0">
building_id IN
<foreach collection="buildingIdList" open="(" separator="," close=")" item="id">
#{id}
</foreach>
</when>
<otherwise>
<!-- 默认全查-->
</otherwise>
</choose>
<if test="storey!=null">
AND c_house.storey=#{storey}
</if>
<if test="areaMin!=null">
AND c_house.area >= #{areaMin}
</if>
<if test="areaMax!=null">
AND c_house.area <= #{areaMax}
</if>
<choose>
<when test="status!=null and status.length>0 and !status[0]">
<!-- 如果为false,则可以查询到非空闲房子-->
</when>
<otherwise>
AND !status
</otherwise>
</choose>
</where>
<if test="areaOrderASC">
ORDER BY c_house.area
</if>
<if test="areaOrderDESC">
ORDER BY c_house.area DESC
</if>
</select>
前后端交互controller层
// 2.处理搜索请求
// 默认显示所有可以选择的房间,放到左侧的框里,如果选择,双击,这条数据跳到右边的框里
@RequestMapping("/query/house")
@ResponseBody
public ResData queryHouse(
// @RequestParam(value = "buildingList", defaultValue = "List[]") List<Building> buildingList, // 楼栋
// Integer storey, // 楼层,没有用到
// Double areaMin,
// Double areaMax,
// @RequestParam(value = "areaOrderASC",defaultValue = "false") Boolean areaOrderASC,
// @RequestParam(value = "areaOrderDESC",defaultValue = "false") Boolean areaOrderDESC
@RequestBody HouseFront houseFront
){
Double areaMax = houseFront.getAreaMax();
Double areaMin = houseFront.getAreaMin();
Boolean areaOrderASC = houseFront.getAreaOrderASC();
Boolean areaOrderDESC = houseFront.getAreaOrderDESC();
Integer storey = houseFront.getStorey();
List<Building> buildingList = houseFront.getBuildingList();
List<Integer> buildingIds = buildingList.stream().map(Building::getId).collect(Collectors.toList());
System.out.println("查询条件:"
+areaMin+"/"
+areaMax+"/"
+buildingIds+"/"
+storey+"/"
);
// 大小的问题
if (!StringUtils.isBlank(areaMin) && !StringUtils.isBlank(areaMax)){
if (areaMin.compareTo(areaMax)>0){
return new ResData(1002, "最小面积不能大于最大面积", null);
}
}
// 这个排序顺序不能两个都是true
if (areaOrderASC && areaOrderDESC){
return new ResData(1003, "排序条件冲突", null);
}
List<House> list = houseService.queryAllNoIntoHouse(buildingIds, storey, areaMin, areaMax, areaOrderASC, areaOrderDESC, true);
list.forEach(System.out::println);
return new ResData(200, "ok", list);
}
前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>新增业主</title>
<link rel="stylesheet" href="/bootstrap/css/bootstrap.min.css">
<script src="/js/jquery-3.5.1.js"></script>
<script src="/bootstrap/js/bootstrap.js"></script>
<script src="/js/axios.min.js"></script>
<script src="/js/vue.min-v2.5.16.js"></script>
</head>
<body>
<div id="app">
<br>
录入业主基础信息:<br>
用户名: <input type="text" v-model="username">
真实姓名:<input type="text" v-model="realname">
电话号码:<input type="text" v-model="tel"><br>
身份证号:<input type="text" v-model="identity">
性别:
<input type="radio" v-model="gender" value="男">男
<input type="radio" v-model="gender" value="女">女
<br>
备注信息:<textarea v-model="notes" rows="3" cols="22"></textarea><br>
<br>
录入选房信息:<br>
<div>
<!-- 搜索所有可以选择的房子-->
楼栋编号:
<select v-model="buildingId">
<option value="">--请选择楼栋--</option>
<option v-for="building in buildingList" :value="building.id">{{building.num}}-{{building.unit}}</option>
</select>
<button @click="addBuildingId">添加楼栋</button>
<button @click="resetSelectBuildsBtn">重选楼栋</button>
<br>
选中的楼栋为:
<select multiple style="width: 100px" @dbclick="removeSelectedBuildingsBtn">
<option v-for="building in selectedBuildingList" :value="building.id">{{building.num}}-{{building.unit}}</option>
</select>
楼层:
<select v-model="selectFloor">
<option value="">-选择楼层--</option>
<option v-for="floors in floorList" :value="floors">{{floors}}层</option>
</select>
面积:
<input type="text" v-model="areaMin" style="width: 50px" placeholder="小">---
<input type="text" v-model="areaMax" style="width: 50px" placeholder="大">
<button @click="areaASC">面积升序</button>
<button @click="areaDESC">面积降序</button>
<button @click="searchHouseBtn">搜索房子</button>
<button @click="searchHouseBtnClr">重置搜索</button><br>
</div>
<!-- TODO:可以选的房子的左侧的框-->
<!-- canSelectHouse-->
可选的房子为:
<select multiple style="width: 200px" @dblclick="selectHouseDbc">
<option v-for="house in canSelectHouse" :value="house.id">
{{house.num}}--{{house.unit}}--{{house.roomNum}}--{{house.area}}
</option>
</select>
选中的房子为:
<select multiple style="width: 200px" @dblclick="removeSelectedHouseDbc">
<option v-for="house in selectedHouse" :value="house.id">
{{house.num}}--{{house.unit}}--{{house.roomNum}}--{{house.area}}平米
</option>
</select>
<br>
<button @click="add">添加</button>
<button @click="reset">重置</button><br>
<br>
</div>
<script>
let app = new Vue({
el:"#app",
data:{
// 首先是用户的基础信息
username:"",
realname:"",
tel:"",
gender:"男",
identity:"",
buildingId:"",
houseId:"",
notes:"",
// 然后是查询的数据
// 然后是选中的楼栋的id,1栋1单元...
floorList : Array.from({ length: 12 }, (v, i) => i + 1), // 最大有12层楼,因此这里可以选择1到12
selectedBuildingList:[], // List<Building> buildingList, // 楼栋
selectFloor:"", // 楼层
areaMin:"", // 面积
areaMax:"", // 面积
// 和排序相关的
areaOrderASC:false,
areaOrderDESC:false,
// 在左侧边框里面显示可以选择的所有房间信息
canSelectHouse:[],
// 在右侧框里面显示已经选择的所有房间信息
selectedHouse:[],
buildingList:[]
},
methods:{
searchHouseBtnClr(){
// 重置搜索
this.selectedBuildingList =[]
this.buildingId = ""
this.selectFloor="" // 楼层
this.areaMin="" // 面积
this.areaMax="" // 面积
// 和排序相关的
this.areaOrderASC=false
this.areaOrderDESC=false
this.queryHouse();
},
// 如果选中了一个楼栋,就添加一个楼栋来,如果有重复的就不添加
addBuildingId(){
let selected = this.buildingList.find(b=>b.id===this.buildingId)
// 这个selected是一个 building对象
console.log(selected)
// 只有selected里面有值,并且没有重复的时候才能添加进来
if (selected && !this.selectedBuildingList.find(b=>b.id===selected.id)){
this.selectedBuildingList.push(selected)
}
},
// 如果双击选中的楼栋,则删除已经选中的楼栋
removeSelectedBuildingsBtn(event){
const optionValue = event.target.value; // 获取双击的对象的值
this.selectedBuildingList = this.selectedBuildingList.filter(building=>building.id != optionValue)
},
// 在可选的房子的框里面双击,则在选中的房子的框里面加这个房子,并且在可选的房子的框里面删除被选的房子
selectHouseDbc(event){
const optionValue = event.target.value; // 获取双击的对象的值
// TODO:注意两点,这个过滤后的还是一个集合,需要获取第一个元素,另外要用== 不要用===
const house = this.canSelectHouse.filter(house=>house.id == optionValue)[0]
console.log(house)
this.selectedHouse.push(house)
this.canSelectHouse = this.canSelectHouse.filter(house=>house.id != optionValue)
console.log(this.canSelectHouse)
console.log(this.selectedHouse)
},
removeSelectedHouseDbc(event){
const optionValue = event.target.value; // 获取双击的对象house
console.log(optionValue)
const house = this.selectedHouse.filter(house=>house.id == optionValue)[0]
this.selectedHouse = this.selectedHouse.filter(house=>house.id !=optionValue)
this.canSelectHouse.push(house)
},
//如果选中了一个房子,就添加一个进来,如果有重复的就不添加
addHouseId(){
const selectedOption = this.allhouseList.find(house=>house.id===this.houseId);
if (selectedOption && !this.houseList.find(house => house.id === selectedOption.id)) {
this.houseList.push(selectedOption);
}
},
removeSelectedOption(event) {
const optionValue = event.target.value;//获取双击的对象的值
console.log(optionValue);
this.houseList = this.houseList.filter(house => house.id != optionValue);
},
add(){
let param = {};
param.username = this.username;
param.realname = this.realname;
param.tel = this.tel;
param.gender = this.gender;
param.identity = this.identity;
param.notes = this.notes;
param.houseList = this.selectedHouse;
axios.post("/owner/add",param)
.then(response=>{
if(response.data.code==200)
{
location.href="/user/ownerPage"
}
else
{
alert(response.data.msg);
}
})
},
// 重新输入用户信息
reset(){
this.username=""
this.realname=""
this.tel=""
this.identity=""
this.notes=""
},
// 重新选择楼栋
resetSelectBuildsBtn(){
this.selectedBuildingList =[]
this.buildingId = ""
},
areaASC(){
this.areaOrderASC=true;
this.areaOrderDESC=false;
this.queryHouse();
},
areaDESC(){
this.areaOrderASC=false;
this.areaOrderDESC=true;
this.queryHouse();
},
// 查询所有可以选择的房间
queryHouse(){
let jsonObj = {}
jsonObj.buildingList=this.selectedBuildingList;
jsonObj.storey=this.selectFloor;
jsonObj.areaMin=this.areaMin;
jsonObj.areaMax=this.areaMax;
jsonObj.areaOrderASC=this.areaOrderASC;
jsonObj.areaOrderDESC=this.areaOrderDESC;
axios.post("/owner/query/house",jsonObj)
.then(response=>{
if (response.data.code==200){
this.canSelectHouse = response.data.data;
}else {
alert(response.data.msg)
}
})
},
searchHouseBtn(){
this.queryHouse();
},
},
mounted(){
// 首先要获得所有可以选择的房子
this.queryHouse();
//查询楼栋下拉列表
axios.get("/build/list/all")
.then(response=>{
this.buildingList = response.data.data;
})
}
});
</script>
</body>
</html>
专门用来前后端交互的实体类
package com.tianju.entity;
import com.alibaba.druid.filter.AutoLoad;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 专门用来和前端交互的一个对象;
* 用于选房页面的复杂查询
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HouseFront {
private List<Building> buildingList;
private Integer storey;
private Double areaMin;
private Double areaMax;
private Boolean areaOrderASC;
private Boolean areaOrderDESC;
}
5.传入Boolean类型的可变长度参数
/**
* 超级管理员能看离职员工和在职员工的信息,
* 其他员工只能看在职员工信息。
* @param su 表示是否是超级管理员,su 为true 时,为超级管理员
* @return
*/
List<User> queryAllManagerUser(
@Param("su") Boolean... su
);
<!-- 修改用户信息,根据用户id查询一条出来-->
<select id="queryManagerById" resultType="user">
<!-- SELECT * FROM user_manager WHERE id = #{id}-->
SELECT * FROM
(SELECT
user_manager.id,
user_role.id AS userRoleId,user_role.role_id AS typeId,user_role.user_id AS userId,
user_manager.username,user_manager.password,user_manager.tel,
user_manager.notes AS userNotes,user_manager.create_time,user_manager.update_time,
user_manager.operator,user_manager.status,user_manager.firstLog,
user_role_type.name AS typeName,user_role_type.notes AS typeNotes
FROM user_manager
LEFT JOIN user_role ON user_manager.id = user_role.user_id
LEFT JOIN user_role_type ON user_role.role_id = user_role_type.id
) t
WHERE t.id = #{id}
<!-- 一般人员只能查询在职员工,超级管理员可以查所有员工-->
<choose>
<when test="su==null or su.length < 1">
AND firstLog !='100' AND status
</when>
</choose>
</select>
6.多个条件排序 ORDER BY num,unit
controller层
@RequestMapping("/list")
@ResponseBody
public ResData buildingList(
@RequestParam(value = "pageNum",defaultValue = "1")Integer pageNum,
@RequestParam(value = "pageSize",defaultValue = "10")Integer pageSize,
@RequestParam(value = "order",defaultValue = "false")Boolean order){
PageInfo<Building> pageInfo = buildingService.queryAll(pageSize, pageNum,order);
System.out.println(pageInfo);
return new ResData(200,"ok",pageInfo);
}
service层
@Override
public PageInfo<Building> queryAll(Integer pageSize,Integer pageNum,Boolean order) {
PageHelper.startPage(pageNum, pageSize);
List<Building> list = buildingMapper.queryAll(order);
return new PageInfo<>(list);
}
mapper层
List<Building> queryAll(Boolean order);
xml文件的sql
<select id="queryAll" resultType="building">
SELECT * FROM c_building
<if test="order">
ORDER BY num,unit
</if>
</select>
7.一条新增影响多个数据库的表@Transactional
controller层
// 3.处理新增用户信息
Boolean addFlag = true;
@RequestMapping("/add")
@ResponseBody
public ResData addOwner(
@RequestBody Owner owner
){
System.out.println(owner);
// 1.判断前端输入的数据全不
// 2.如果确认不新添房子,则只修改user_owner表,则该用户不能登陆账号
// 3.如果新增了房子,则修改user_owner表,c_house表,c_owner_house表
if (StringUtils.isBlank(owner.getUsername(),owner.getRealname(),owner.getIdentity(),owner.getGender())){
return new ResData(1001, "必填项为空", null);
}
if (!StringUtils.isLegalPhone(owner.getTel())){
return new ResData(1002, "手机号码不合法", null);
}
// TODO:这样可以吗???
if (addFlag){
if (owner.getHouseList().size()<1){
addFlag = false;
return new ResData(2001, "确定新增一条未选择房间的业主?", null);
}
}
// 初始化一下密码,手机号前4位
owner.setPassword(owner.getTel().substring(0,4));
// 获取session
User user = (User) session.getAttribute("user");
if (user!=null){
owner.setOperator(user.getOperator());
}
Integer flag = ownerService.add(owner);
if (flag<1){
return new ResData(3001, "系统繁忙,请稍后重试", null);
}
addFlag = true; // 新增成功再置为true,下一条就会再次判断是不是没填
return new ResData(200,"新增用户信息成功",null);
}
service层@Transactional
@Transactional
@Override
public Integer add(Owner owner) {
// 如果新用户只是意向客户
if (owner.getHouseList().size()<1){
owner.setHouseNum(0);
return ownerMapper.add(owner);
}
// 买房的客户变成了业主
Integer num = 0; //影响数据库的数据的行数
ownerMapper.add(owner);
for (House house:owner.getHouseList()){
// 房间状态改为入住的状态
houseMapper.intoHouse(house.getId());
// 房屋-业主对应表新增一条数据
houseMapper.addOwnerHouse(owner.getId(), house.getId());
num +=2;
}
return num;
}
<update id="intoHouse">
UPDATE c_house SET into_date = NOW(),status=1 WHERE id=#{id}
</update>
<insert id="addOwnerHouse">
INSERT INTO c_owner_house(ownerId,houseId) VALUES (#{ownerId},#{houseId})
</insert>
mybatis使用报错集锦
1.忘记加 resultType=“opus”
报错信息:
Error querying database. Cause: org.apache.ibatis.executor.ExecutorException: A query was run and no Result Maps were found for the Mapped Statement ‘com.tianju.dao.OpusMapper.queryByAuthorIdAndLikeName’. It’s likely that neither a Result Type nor a Result Map was specified.
报错原因:
查询返回值类型没写
解决方案:
加上resultType=“opus”,如下:
<!-- 多种条件查询-->
<select id="queryByAuthorIdAndLikeName" resultType="opus">
SELECT t_opus.*,tt.name AS typename,tu.username
FROM t_opus
LEFT JOIN t_types tt ON t_opus.typeId = tt.id
LEFT JOIN user_tab tu ON t_opus.authorId = tu.id
<where>
<if test="authorId!=null">
authorId = #{authorId}
</if>
<if test="name!=null and name!=''">
AND t_opus.name LIKE #{name}
</if>
</where>
ORDER BY t_opus.id DESC
</select>
2.前端显示list页面数据为空
问题描述:
pageHelper里面的没有数据,前端显示为空:
PageInfo{pageNum=0, pageSize=0, size=0, startRow=0, endRow=0, total=0, pages=0, list=null, firstPage=0, prePage=0, nextPage=0, lastPage=0, isFirstPage=false, isLastPage=false, hasPreviousPage=false, hasNextPage=false, navigatePages=0, navigatepageNums=null}
原因分析:
pageHelper有顺序要求
解决方案:
/**
* 分页在service层完成,利用pageHelper 在service层做完分页的事情
*/
@Override
public PageInfo<Opus> queryByAuthorIdAndLikeName(String name, Integer authorId, Integer pageNum,Integer pageSize) {
// 先要用pageHelper的 分页,然后执行查询
PageHelper.startPage(pageNum, pageSize);
List<Opus> list = opusMapper.queryByAuthorIdAndLikeName(name, authorId);
PageInfo<Opus> pageInfo = new PageInfo<>(list);
return pageInfo;
}
3.由于mybatis版本引起的问题
报错信息:
org.apache.ibatis.exceptions.PersistenceException:
Error querying database. Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named ‘username’ in ‘class java.lang.String’
Cause: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named ‘username’ in ‘class java.lang.String’
报错原因
如果3.4.5版本,3.4开头的就是低版本,并且username要在动态sql中使用,即,if,where,中使用,则一个参数也需要加@param,如果是3.5.9以上版本,则可以不加
解决方案:
1.UserMapper里面加@param
// 如果3.4.5版本,3.4开头的就是低版本,并且username要在动态sql中使用
// 即,if,where,中使用,则一个参数也需要加@param,如果是3.5.9以上版本,则可以不加
List<User> findByUsernameSQL(@Param("username") String username);
2.mybatis版本换成3.5以上
<!-- mybatis 框架-->
<!-- 小版本会导致userMapper findByUsernameSQL-->
<!-- 3.5.9-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
在项目中的案例:
接口java文件
List<Company> queryByLikeName(@Param("name") String name);
xml文件
<select id="queryByLikeName" resultType="company">
SELECT com_company.*,com_type.name AS typename,com_user.username AS username FROM com_company
LEFT JOIN com_type ON com_company.type_id=com_type.id
LEFT JOIN com_user ON com_company.user_id=com_user.id
<where>
<if test="name!=null and name !=''">
com_company.name LIKE #{name}
</if>
</where>
</select>
可以在这里看相关的包
https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api
4. but found: 11:返回值类型错误
报错信息:
org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 11
报错原因:
类型错误,如果查询出的结果可能是多个,则需要用List进行接收
解决方案:
改成list
List<User> findByUsernameSQL(@Param("username") String username);
5.Mapper.XML文件中的id重复
报错信息
15-Jun-2023 10:59:46.335 信息 [http-nio-8080-exec-7] org.apache.catalina.core.ApplicationContext.log 将servlet[com.tianju.servlet.user.LoginServiceVue]标记为不可用
15-Jun-2023 10:59:46.335 严重 [http-nio-8080-exec-7] org.apache.catalina.core.StandardWrapperValve.invoke 分配异常的servlet [com.tianju.servlet.user.LoginServiceVue]
java.lang.IllegalArgumentException: Mapped Statements collection already contains value for com.tianju.dao.OpusMapper.removeById
报错原因:
mapper中存在id重复的值
解决方案:
修改其中一个mapper的id
6.删除不生效:Mapper.xml文件中的<delete写成了select
问题描述:
在前端点击删除按钮,刷新前端后该数据依然存在,数据库中的数据确实被删除;如果项目重启,前端才没有该条数据,开始以为数缓存的问题;
这个问题比较奇怪,尝试了清除mybatis的缓存等方法都没有解决,
错误原因:
这里的delete,写成了select
解决方案:改成delete
<!-- TODO:如果这里的delete,写成了select-->
<delete id="removeById" parameterType="integer">
DELETE FROM t_opus WHERE id = #{id}
</delete>
7.修改数据:报500异常,update 的逗号,没加
报错信息:
Error updating database. Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘intro=‘123’,
updateTime=now() WHERE id=47’ at line 11
SQL: UPDATE t_opus SET name=?, typeId=? intro=?, updateTime=now() WHERE id=?
Cause: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘intro=‘123’,
updateTime=now() WHERE id=47’ at line 11
排查bug的顺序:
(1)先看前端,报500异常,说明java代码有问题;
(2)在后台的tomcat localhost log里面定位错误是SQL语句的问题;
(3)在service这里可以看到执行的sql,如下
UPDATE t_opus SET name=?, typeId=? intro=?, updateTime=now() WHERE id=?
(4)最终的原因是OpusMapper.xml里面的动态sql写错了;
解决方法:加上逗号
OpusMapper.java接口
/**
* 修改一条图书信息
*/
Integer updateById(@Param("opus") Opus opus);
OpusMapper.xml中对应的动态sql
<!-- 如果@Param("opus") 和上面对比-->
<update id="updateById">
UPDATE t_opus SET
<if test="opus.name!=null and opus.name!=''">
name=#{opus.name},
</if>
<!-- 如果的Integer类型的id,加上了不为''的条件-->
<if test="opus.typeId!=null">
<!-- 如果这里没有加 逗号 -->
typeId=#{opus.typeId},
</if>
<if test="opus.intro!=null and opus.intro!=''">
intro=#{opus.intro},
</if>
updateTime=now() WHERE id=#{opus.id}
</update>
8.xml文件和java文件名不一致:
报错信息:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.tianju.dao.CompanyMapper.queryByLikeName
原因解析:
后台显示sql并没有执行,再结合 Invalid bound statement (not found):的报错信息,检查文件名确实不一致
9.在xml文件中的resultType写错映射对象
报错信息:
org.apache.catalina.core.StandardWrapperValve.invoke 分配异常的servlet [com.tianju.servlet.company.CompanyListServlet]
java.lang.ClassNotFoundException: Cannot find class: user
10.日期类型判断时加了!=”引发的异常
报错信息:
Cause: java.lang.IllegalArgumentException: invalid comparison: java.util.Date and java.lang.String
<!-- TODO:数字和日期类型不要加 createTime!=''-->
<if test="createTime!=null and createTime!=''">
create_time=#{createTime},
</if>
解决方案:
<if test="createTime!=null">
create_time=#{createTime},
</if>
总结
1.mybatis可以实现SQL语句和Java代码的解耦;
2.mybatis使用,tomcat的war包,和spring的jar包,分页的拦截器;
3.mybatis项目应用初步,SqlSessionUtils工具类,泛型的方式;
4.多条件查询<where,choose,when,otherwise,foreach,if>,排序order;
5.事务回滚,要么都成功,要么都失败,@Transactional注解;
6.在tomcat和spring框架下,常见的报错集锦
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/165115.html