crud最常用
1.删除操作,用了rest风格的请求,还有post请求的三种方式
delHouse(id){ this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { //1.rest风格的delete删除请求 /* this.$http.delete('/house/' + id).then(resp=>{ console.log('resp.data',resp.date) this.$message({ type: 'success', message: '删除成功!' }); }).catch(e=>{ console.log(e) }) */ //2.1.Post请求==>Content-Type:application/x-www-form-urlencoded;charset=UTF-8 /* const param = new URLSearchParams(); param.append('id',id) this.$http.post('/house/del',param).then(resp=>{ console.log(resp.data) this.$message({type: 'success',message: '删除成功!'}); }).catch(e=>{ console.log(e) }) */ //2.2post请求发送==>Content-Type: application/x-www-form-urlencoded;charset=UTF-8 /* let param = {id:id} this.$http.post('/house/del',querystring.stringify(param)).then(resp=>{ this.$message({type: 'success',message: '删除成功!'}); }).catch(e =>{ console.log(e) }) */ //2.3.(引入qs库,) //post请求发送==>Content-Type: application/x-www-form-urlencoded;charset=UTF-8 let param = {id:id} this.$http.post('/house/del',qs.stringify(param)).then(resp=>{ if(resp.data.code === 200){ this.queryHouseList() this.$message.success('删除成功!'); }else{ this.$message.error(resp.data.msg) } }).catch(e=>{ console.log(e) }) }).catch(() => { this.$message({ type: 'info', message: '已取消删除' }); }); },
2.编辑(修改)操作==>弹出一个模态框,先清空模态框,再进行赋值,
(模态框可以先处理好里面得东西,然后再让他弹出,那样就不会有时间差)
//提交修改 submitEdit(){ this.$http.put('/house',this.editForm).then(resp =>{ if(resp.data.code === 200){ this.$message.success('修改成功') this.editFormVisible = false this.queryHouseList() } }).catch(e=>{ console.log(e) }) }, //编辑 editHouse(house){ this.editForm ={ province: '', city: '', area: '', rentMode: '', houseType: '', direction: '', address: '', rent: '', } console.log('house',house) this.$http.get('/area/' + house.province).then(resp=>{ console.log('resp',resp) if(resp.data.code ===200){ this.editArea.cityList = resp.data.data this.$http.get('/area/' + house.city).then(resp=>{ if(resp.data.code ===200){ this.editArea.areaList = resp.data.data //this.editForm = house==>这种直接赋值会出现问题 //在表单里一修改,页面就会随之修改,数据库没变化 //(与java中的引用船只类似) this.editForm.id = house.id this.editForm.province = house.province this.editForm.city = house.city this.editForm.area = house.area this.editForm.rentMode = house.rentMode this.editForm.houseType = house.houseType this.editForm.direction = house.direction this.editForm.address = house.address this.editForm.rent = house.rent this.editFormVisible = true } }).catch(e=>{ console.log(e) }) } }).catch(e=>{ console.log(e) }) },
3.在后台把数据库的字段查出来给前端页面进行赋值,
这样做比写死好用多了,在此代码中调用一个方法,查出了三个字段
//查询字典列表(租赁方式,户型,朝向) queryDict(groupId){ // let url = '/dict?groupId=' + groupId if(groupId){ this.$http.get('dict',{ params:{ groupId:groupId } }).then(res=>{ if(res.data.code === 200){ let result = res.data.data if(groupId ==='rent_mode'){ this.dict.rentModeList = result }else if(groupId==='house_type'){ this.dict.houseTypeList = result }else{ this.dict.directionList = result } } }).catch(e=>{ console.log(e) }) } },
-------------------------------------------------------------------
//初始化
created() {
this.queryHouseList()
this.queryProvinceList()
this.queryDict('rent_mode')
this.queryDict('house_type')
this.queryDict('direction')
},
-----------------------------------------------------------------
//sql语句
<select id="queryList" parameterType="String" resultType="Dict">
select id,name,value from t_dict where group_id = #{value} order by sort
</select>
------------------------以下是前端页面-------------------------
4.省市区级联查询
<!-- 横向排列省市区 -->
<el-row :gutter="10">
<el-col :span="8">
<el-form-item label="所在省" prop="province">
<el-select v-model="queryForm.province" @change="queryCityList">
<el-option label="请选择" value=""></el-option>
<el-option v-for="area in area.provinceList" :key="area.name"
:label="area.name" :value="area.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="所在市" prop="city">
<el-select v-model="queryForm.city" @change="queryAreaList">
<el-option label="请选择" value=""></el-option>
<el-option v-for="city in area.cityList" :key="city.name"
:label="city.name" :value="city.id"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="所在区" prop="area">
<el-select v-model="queryForm.area" >
<el-option label="请选择" value=""></el-option>
<el-option v-for="area in area.areaList" :key="area.name"
:label="area.name" :value="area.id"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
-----------------------------------------------------------------------------------------------------------------------------
//查区 queryAreaList(cityId){ this.area.areaList = [] this.queryForm.area = '' this.$http.get('/area/' + cityId).then(resp=>{ if(resp.data.code===200){ this.area.areaList = resp.data.data } }).catch(e=>{ console.log(e) }) }, //查市 queryCityList(provinceId){ this.area.areaList = [] this.area.cityList = [] this.queryForm.area = '' this.queryForm.city = '' this.$http.get('/area/' + provinceId).then(resp=>{ if(resp.data.code===200){ this.area.cityList = resp.data.data } }).catch(e=>{ console.log(e) }) }, //查省 queryProvinceList(){ this.$http.get('/area/-1').then(resp=>{ if(resp.data.code===200){ this.area.provinceList = resp.data.data } }).catch(e=>{ console.log(e) }) },
5.分页
<el-pagination style="margin-top:30px" background :current-page="pageNum" :page-size="pageSize" :page-sizes="[1, 2, 5, 10, 15, 20]" layout="total,sizes,prev, pager, next,jumper" :total="total" @size-change="pageSizeChange" @current-change="pageNumChange"> </el-pagination>
------------------------------------------------------------
/* 分页 */
pageSizeChange(pageSize){
this.pageSize = pageSize
this.queryHouseList()
},
pageNumChange(pageNum){
this.pageNum = pageNum
this.queryHouseList()
},
//点击查询,第一页
clickQuery(){
this.pageNum = 1
this.queryHouseList()
},
6.登录界面(8是6的登录后台)
重置表单用的是ref,在做的时候一直报validate未定义,
结果是this.$refs.loginFormRef.validate中的loginFormRef中的首字母l写成了大写
<template> <el-form ref="loginFormRef" :rules="loginFormRules" :model="loginForm"> <el-form-item label="用户名" prop="name" > <el-input v-model="loginForm.name" placeholder="用户名"></el-input> </el-form-item> <el-form-item label="密码" prop="password"> <el-input type="password" v-model="loginForm.password" placeholder="密码"></el-input> </el-form-item> <el-form-item> <el-button type="primary" @click="login">登录</el-button> <el-button @click="resetLoginForm">重置</el-button> </el-form-item> </el-form> </template> <script> export default { data() { return { loginForm:{ name:'', password:'', }, loginFormRules:{ name:[ {required: true, message: '请填写正确的用户名', trigger: 'blur'}, ], password:[ {required: true, message: '请填写正确的用户密码', trigger: 'blur'}, ], } } }, methods: { login(){
任一表单项被校验后触发 被校验的表单项 prop 值,校验是否通过, this.$refs.loginFormRef.validate(valid =>{ if(valid){ let param = new URLSearchParams(); param.append("name",this.loginForm.name) param.append("password",this.loginForm.password) this.$http.post('/user/login',param).then(resp=>{ if(resp.data.code === 200){ this.$router.push("/") window.sessionStorage.setItem('token',resp.data.data) } else { this.$message.error(resp.data.msg); } }) }else{ console.log('error submit!!') return false; } }) }, resetLoginForm(){ this.$refs.loginFormRef.resetFields() } }, created() { }, } </script> <style scoped> </style>
==========================================================main.js里的拦截器=============================================
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import './assets/css/et.css';
import axios from 'axios'
axios.defaults.baseURL = 'http://localhost:8000/house-app'
Vue.prototype.$http = axios
Vue.prototype.path = 'http://localhost:8000/house-app'
Vue.config.productionTip = false
Vue.use(ElementUI);
//设置全局前置路由守卫
//to即将进入的目标,from即将离开的路由,next:要调用的方法
router.beforeEach((to,from,next)=>{
console.log('to',to)
if(to.path === '/login'){//判断权限
return next()
} else {//查看session中有无token
let token = sessionStorage.getItem('token')
if(token){
return next()
}else{
return next('/login')
}
}
})
//设置axios请求拦截器
axios.interceptors.request.use(config =>{
console.log(config)
if(config.url==='/user/login'){
return config
} else {//如果不是登录请求,则先获取token,放到请求头中
let token = sessionStorage.getItem('token')
if(token){
config.headers.Access_Token = token//token放到请求头Access_Token中//这个请求头需要填写在后台跨域中
return config
}else{
alert("没有登录信息")
router.push('/login')
return Promise.reject('用户未登录')/* 返回一个带有拒绝原因的Promise对象。 */
}
}
},error=>{
return Promise.reject(error)
})
//响应拦截器
axios.interceptors.response.use(response =>{
console.log('response',response)
if(response.config.url === '/user/login'){
return response
} else {
if(response.data.code === 999 ){
router.push('/login')
return Promise.reject("用户认证失败")
}else {
sessionStorage.setItem('token',response.headers.token)
return response
}
}
},error=>{
return Promise.reject(error)
})
new Vue({
router,
render: h => h(App)
}).$mount('#app')
7.重置表单
7.1
resetLoginForm(){ this.$refs.loginFormRef.resetFields() }
7.2 resetForm(formName){ this.$refs[formName].resetFields(); },
7.3
this.$nextTick(() => {
this.$refs[formName].resetFields(); });
8.登录后台
@RestController @RequestMapping("/user") @Slf4j public class UserController { @Autowired UserService userService; @PostMapping("/login") public Result login(@RequestParam String name, @RequestParam String password){ User user = userService.getUser(name); //1.判断用户 if(ObjectUtils.isEmpty(user)){ log.warn("用户名错误"); return Result.failed("用户名或密码错误"); } //2.验证密码 password = DigestUtils.md5Hex(password); if(!StringUtils.equals(user.getPassword(),password)){ return Result.failed("用户名或密码错误"); } //3.创建token AccessToken accessToken = new AccessToken(name); String jsonToken = JSONObject.toJSONString(accessToken); //4.加密 String token = EncrypUtil.encrypt(jsonToken); //5.返回前端 return Result.success(token); } }
----------------------------AccessToken 类--------------------------------
package com.etoak.common;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class AccessToken {
//用户名
private String username;
//过期时间
private Long expire;
public AccessToken(String username){
this.username =username;
//暂时默认两分钟
this.expire = System.currentTimeMillis() + 1000*60*2;
}
}
------------------------依赖-------------
<!-- 格式对象转换 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>
<!-- 加解密工具包 -->
<dependency>
<groupId>org.jasypt</groupId>
<artifactId>jasypt</artifactId>
<version>1.9.2</version>
</dependency>
</dependencies>
-----------------------------mapper接口--------------------------------
==========================================LoginInterceptor拦截器==================================================================
package com.etoak.interceptor;
import com.alibaba.fastjson.JSONObject;
import com.etoak.bean.User;
import com.etoak.common.AccessToken;
import com.etoak.common.Result;
import com.etoak.service.UserService;
import com.etoak.util.EncryptUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
UserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
/* log.info("Request Method - {}" , request.getMethod() );*/
String method = request.getMethod();
if(StringUtils.equals(method.toUpperCase(),"OPTIONS")){//1.是option请求直接放行
return true;
}
//2.判断请求头中是否有Access_Token,如果没有返回前端
String accessTokenHeader = request.getHeader("Access_Token");
if(StringUtils.isEmpty(accessTokenHeader)){
log.warn("没有Access_Token");
this.noAuth(response,"没有认证信息");
return false;
}
//3.验证Access_Token的有效期
try{
String accessTokenJson = EncryptUtil.decrypt(accessTokenHeader);
AccessToken accessToken = JSONObject.parseObject(accessTokenJson, AccessToken.class);
Long expire = accessToken.getExpire();//得到的是什么时候到期
if(System.currentTimeMillis() - expire >=0 ){
log.warn("Access_Token超时");
this.noAuth(response,"认证信息超时");
return false;
}
//4.验证用户名是否正确
//如果不为空,则允许访问,并且设置新的token,放到响应头中
User user = userService.getUser(accessToken.getUsername());
if(ObjectUtils.isEmpty(user)){
log.warn("非法用户访问-{}", accessToken.getUsername());
this.noAuth(response,"非法用户");
return false;
}
accessToken = new AccessToken(accessToken.getUsername());
String token = EncryptUtil.encrypt(JSONObject.toJSONString(accessToken));
response.setHeader("token",token);
}catch (Exception e){
log.error(e.getMessage(),e);
this.noAuth(response,"");
return false;
}
return true;
}
//公共方法,返回没有权限
private void noAuth(HttpServletResponse response,String msg) throws IOException {
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json;charset=UTF-8");
msg = StringUtils.isNotEmpty(msg) ? msg : Result.NO_AUTH_MSG;
Result result = Result.noAuth(msg);
PrintWriter writer = response.getWriter();
writer.print(JSONObject.toJSONString(result));
writer.flush();
writer.close();
}
}
9.跨域
9.1先过滤拦截所有请求,处理跨域问题,
@Configuration public class FilterConfig { /** * Spring Boot注册过滤器 * 自定义Filter需要两个步骤:(跨域实现了Filter) * 实现Filter【javax.servlet.Filter】接口,实现Filter方法 * 添加 @Configuration 注解,将自定义Filter加入过滤链 * @return */ //之前做springmvc是在web.xml文件中配置,而现在是springboot工程,没有web.xml文件,所以需要自己写一个类配置Bean @Bean public FilterRegistrationBean<CrossDomainFilter> crossDomainFilter(){ FilterRegistrationBean<CrossDomainFilter> regBean = new FilterRegistrationBean<>(); // <filter-class> regBean.setFilter(new CrossDomainFilter());//注册了写着跨域的类 // <url-pattern> regBean.addUrlPatterns("/*");//拦截所有请求,进入CrossDomainFilter先进行跨域 regBean.setOrder(1);//优先级最高 return regBean; } }
-----------------------------9.2跨域设置------------------------------------
@Slf4j
public class CrossDomainFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("初始化跨域过滤器");
}
@Override
public void doFilter(ServletRequest req,
ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 允许所有的请求域名访问我们的跨域资源,可以固定单个或者多个内容
httpResponse.setHeader("Access-Control-Allow-Origin", "*");//
// httpResponse.setHeader("Access-Control-Allow-Origin", "http://localhost:9090");// 允许所有的请求域名访问我们的跨域资源,可以固定单个或者多个内容
httpResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE,PUT");// 允许何种请求方法访问该跨域资源服务器
httpResponse.setHeader("Access-Control-Max-Age", "3600");// 预检请求的有效期,单位为秒。有效期内,不会重复发送预检请求
httpResponse.addHeader("Access-Control-Allow-Headers",
"Accept,authorization,Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With");// 允许所有的请求header访问,可以自定义设置任意请求头信息 后期加上 authorization
httpResponse.setHeader("Access-Control-Allow-Credentials", "true");// 是否允许用户发送、处理cookie
//如果额外设置自己的头需要在这定义
httpResponse.setHeader("Access-Control-Expose-Headers", "Access-Token");
chain.doFilter(req, httpResponse);
}
@Override
public void destroy() {
}
}
10.application.yml文件
server: port: 8000 servlet: context-path: /house-app spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver ##时区问题 url: jdbc:mysql://127.0.0.1:3306/et2006?serverTimezone=UTC username: root password: etoak servlet: multipart: max-file-size: 2MB mybatis: ##给包下边的类起别名 type-aliases-package: com.etoak.bean mapper-locations: classpath:mappers/*.xml pagehelper: ##分页合理化 reasonable: true ##给包下执行的代码添加日志级别debug logging: level: com.etoak.mapper: debug ##图片上传路径 upload: dir: d:/upload
11.全局异常处理(controller)
(
@RestControllerAdvice //@ControllerAdvice + @ResponseBody==>
通过对异常的拦截,统一返回对异常的处理
)
---------------以下是springmvc的异常处理------------------------------- @Slf4j //当controller层抛出异常就会被这个注解拦截 @ControllerAdvice public class GlobalExceptionHandler { //表示拦截RuntimeException异常,Runtime异常下的子异常也会被拦截 @ExceptionHandler(RuntimeException.class) public ModelAndView handle(RuntimeException e) { log.error(e.getMessage(),e); //System.out.println("异常-->" + e); ModelAndView mv = new ModelAndView(); mv.setViewName("student/upload"); mv.addObject("error",e.getMessage()); return mv; } //添加对RunimeException的子异常处理方法 @ExceptionHandler(StudentParamException.class) public ModelAndView handle(StudentParamException e) { System.out.println("StudentParamException异常-->" + e); ModelAndView mv = new ModelAndView(); mv.setViewName("student/upload"); mv.addObject("error",e.getMessage()); return mv; } @ExceptionHandler(UserLoginException.class) public ModelAndView handle(UserLoginException e) { log.error(e.getMessage() , e); ModelAndView mv = new ModelAndView(); mv.setViewName("login"); mv.addObject("error",e.getMessage()); return mv; } }
------------------------------------以下是springboot做的异常处理------------------------------------------
package com.etoak.common;
import com.etoak.exception.HouseException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice //@ControllerAdvice + @ResponseBody==>
// 通过对异常的拦截,统一返回对异常的处理
@Slf4j
public class GlbalExceptionHandler {
@ExceptionHandler(HouseException.class)
public Result handle(HouseException e){
log.error(e.getMessage(),e);
return Result.failed(e.getMessage());
}
}
12.文件上传
/** 读取默认配置文件的参数 */ @Value("${upload.dir}") private String destDir; //文件上传 @PostMapping("/upload") public Result<String> upload(MultipartFile file) throws Exception{ //获得源文件名称和后缀 String originalFilename = file.getOriginalFilename(); String suffix = FilenameUtils.getExtension(originalFilename); //创建新的文件名称 String uuid = UUID.randomUUID().toString().replaceAll("-",""); String filename = String.format("%s%s%s",//占位符(占了三个参数),拼接三个参数 uuid,".",suffix); //创建目标文件夹 File destDirectory = new File(destDir); if(!destDirectory.exists()){ destDirectory.mkdirs(); } //创建目标文件.并上传 File destFile = new File(destDirectory,filename); file.transferTo(destFile); String pic = "/pic/" + filename;//是为了之后拿图片的时候有个路径 log.info("pic path-{}" , pic); return Result.success(pic); }
13.密码加密
package com.etoak.util; //加密工具 import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; import org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig; public class EncrypUtil { private static final StandardPBEStringEncryptor encryptor; static { encryptor = new StandardPBEStringEncryptor(); EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig(); config.setAlgorithm("PBEWithMD5AndDES");//加密算法 config.setPassword("et2006_+-");//密码加盐 encryptor.setConfig(config); } /*加密方法*/ public static String encrypt(String text){ return encryptor.encrypt(text); } /*解密方法*/ public static String decrypt(String password){ return encryptor.decrypt(password); } public static void main(String[] args) { String encrypt = encryptor.encrypt("18902161379"); System.out.println(encrypt); String en = "9LzaT5W0ucfqgquKhkknYXRGLaqPVxZ4FNXjNJ7eXYrH/BFfnMDCTqdMUNV8yC0aXJNM70Gm9MU="; System.out.println(encryptor.decrypt(en)); } }
14.后台校验
---------------------serviceImpl层--------------------
@Override public void addHouse( House house) { //校验house ValidationUtil.validate(house); //先校验house,然后再给他赋值,要不会报空 // (用的是postman,传的空对象,所以house.getArea()得到的就是空) house.setAreaName(houseMapper.queryAreaName(house.getArea()).getName()); houseMapper.addHouse(house); }
-----------------------ValidationUtil类-------------------------
//后台校验工具类**自己写的类
public class ValidationUtil {
private static final Validator validator;
static{
ValidatorFactory factory =
Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
public static void validate(Object object){
Set<ConstraintViolation<Object>> constraints = validator.validate(object);
//如果为空,表示校验失败
if(CollectionUtils.isNotEmpty(constraints)){
StringBuffer message = new StringBuffer();
constraints.forEach(x->{
String msg = x.getMessage();
message.append(msg).append(";");
});
throw new HouseException(message.toString());
}
}
}
15mapper的sql语句
<?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.etoak.mapper.HouseMapper"> <cache flushInterval="1800000"></cache> <select id="queryList" parameterType="com.etoak.common.HouseRequestVo" resultType="HouseVo"> select t.id,t.province,t.city,t.area,t.area_name as areaName,t.rent_mode as rentMode, t2.name as rentModeName,t.house_type as houseType,t3.name as houseTypeName,t.direction, t4.name as directionName,t.rent,t.address,t.pic,t.create_time as createTime from t_house t left join t_dict t2 on t.rent_mode = t2.value and t2.group_id = 'rent_mode' left join t_dict t3 on t.house_type = t3.value and t3.group_id = 'house_type' left join t_dict t4 on t.direction = t4.value and t4.group_id = 'direction' <where> <if test="province !=null and province != 0"> and t.province = #{province} </if> <if test="city != null and city != 0"> and t.city = #{city} </if> <if test="area !=null and area != 0"> and t.area = #{area} </if> <if test="rentMode != null and rentMode != ''"> and t.rent_mode = #{rentMode} </if> <if test="rentMapList != null and rentMapList.size() != 0"> and <foreach collection="rentMapList" item="rentMap" open="(" close=")" separator="or"> t.rent between #{rentMap.start} and #{rentMap.end} </foreach> </if> <if test="directionList != null and directionList.size() != 0"> and t.direction in <foreach collection="directionList" item="direction" open="(" close=")" separator=","> #{direction} </foreach> </if> <if test="houseTypeList != null and houseTypeList.size() != 0"> and t.house_type in <foreach collection="houseTypeList" item="houseType" open="(" close=")" separator=","> #{houseType} </foreach> </if> </where> order by t.create_time desc </select> <select id="queryAreaName" parameterType="int" resultType="Area"> select * from t_area where id = #{value} </select> <insert id="addHouse" parameterType="House"> insert into t_house(province,city,area,area_name,rent_mode,house_type,direction,rent,address,pic,create_time) values (#{province},#{city},#{area},#{areaName},#{rentMode},#{houseType},#{direction},#{rent},#{address},#{pic},now()) </insert> <update id="updateHouse" parameterType="House" > update t_house <set> <if test="rent != null and rent != 0"> rent = #{rent}, </if> <if test="rentMode != null and rentMode != ''"> rent_mode = #{rentMode}, </if> <if test="houseType != null and houseType !=''"> house_type = #{houseType}, </if> <if test="direction != null and direction != ''"> direction = #{direction}, </if> <if test="address != null and address != ''"> address = #{address}, </if> create_time = now() </set> where id = #{id} </update> <delete id="deleteHouse" parameterType="int"> delete from t_house where id = #{value} </delete> </mapper>