项目2要做的事情
给大家提供前端,大家做后端的开发
Vue:后台管理(面向管理员)、前端
微信小程序:前台商城(面向用户)、前端
需要搭建一个SpringBoot的应用,以小组为单位搭建SpringBoot应用
后台管理(后天)
182.92.235.201 抓包
抓包是为了
- 请求URL → @RequestMapping
- 请求方法 → 请求方法限定、作为Json数据判断的一个条件
- 请求参数(是否是JSON) → 判断数据的值
- 响应结果 → 封装Handler方法的返回值
当然你也可以看前端
前端应用如果要自己开发,大家可以自己把前端跑起来
前端应用:直接放到tomcat/webapps/ROOT
使用bin/startup.bat(sh)把tomcat跑起来
有的同学的tomcat跑不出,JAVA_HOME要配置;如果JAVA_HOME配置了还跑不起来 → 删掉tomcat,重新下载一个,然后解压
前台商城(大后天)
微信开发者工具 → 搜索引擎上下载了一个(稳定版)
有一个配置需要大家来做
时间安排
今天到下周四上午(13号) → 项目演示
项目奖励:3(300) 2(400) 1(500)
评分标准:35(完整性) 35(Bug) 15(表达) 15(亮点)
项目进度表
【腾讯文档】36th项目二进度表
https://docs.qq.com/sheet/DSkJCZVVCSlljdFRY
分工、进度
提供SQL脚本
后缀为sql的文件,sql脚本里放的就是sql语句
使用sql脚本
开发
Git管理应用
在工作区的根目录创建SpringBoot
搭建SpringBoot应用
IDEA中使用Git
使用鼠标右键 → Git 包含具体的操作
有一个show history的功能还可以
可以在IDEA中整合Git的命令行,需要配置一下
开发Handler方法
解决跨域问题
SpringBoot应用提供一个CorsFilter → 提供一个组件 → 配置类
@Configuration
public class CorsConfig {
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址
corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
return corsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig()); // 4 对接口配置跨域设置
return new CorsFilter(source);
}
}
也可以在配置类里使用WebMvcConfigurer提供的方法来解决
建议大家在项目中使用配置类这个方式(上面的方式)
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
//这种方式,引入其他filter时有可能导致跨域失效
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*");
}
}
工具
帮你将Json识别为对应的JavaBean → GsonFormmat (plus)
识别为对应的JavaBean
分页插件
PageHelper
- pagehelper-spring-boot-starter
- pagehelper.helper-dialect=mysql
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper-spring-boot-starter -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.1</version>
</dependency>
pagehelper:
helper-dialect: mysql
使用PageHelper
在执行查询之前开启分页信息,page、limit
PageHelper会在预编译时拼接sql语句,拼接分页相关的sql
<sql id="user_column_list">
id,username,password,gender,last_login_time as lastLoginTime,nickname,mobile,avatar,status,add_time as addTime,update_time as updateTime,deleted
</sql>
<select id="select" resultType="com.cskaoyan.bean.User">
select <include refid="user_column_list"/>
from market_user
<where>
<if test="username != null">
username = #{username}
</if>
</where>
order by ${sort} ${order}
</select>
Integer page = param.getPage();//页码
Integer limit = param.getLimit();//数据量
String sort = param.getSort();//排序列
String order = param.getOrder();//desc\asc
PageHelper.startPage(page, limit);
List<KeyWordListVo.ListDTO> listDTOS = keyWordDao.SelectKeyWordList(param, keyword, url);
PageInfo<KeyWordListVo.ListDTO> listDTOPageInfo = new PageInfo<>(listDTOS);
int pages = listDTOPageInfo.getPages();
long total = listDTOPageInfo.getTotal();
日志
logging.level
logging:
level:
# key是包名、value是日志级别
com.cskaoyan.mapper: debug
项目能够进到首页
需要有两个接口 /admin/auth/login 和 /admin/auth/info(里面的数据是构造的)
先给大家提供这两个接口,shiro框架 → 视频课程
逆向工程
开发繁琐的地方
数据库给到大家了,表 → 与之对应的JavaBean、Mapper接口、映射文件 → 能够带来可以直接使用的方法
→ 基本上单表能用到的SQL都可以帮你执行
引入依赖
mybatis-generator-core、mysql-connnector-java
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--如果要使用mybatis的话就引入mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
配置文件
连接:datasource的配置
javabean目录的配置
mapper接口目录的配置
mapper映射文件目录的配置
表
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mall36"
userId="root"
password="123456">
<!--是否去除同名表-->
<property name="nullCatalogMeansCurrent" value="true"/>
</jdbcConnection>
<!-- javaModelGenerator javaBean生成的配置信息
targetProject:生成PO类的位置
targetPackage:生成PO类的类名-->
<javaModelGenerator targetPackage="com.cskaoyan.bean"
targetProject=".\src\main\java">
<!-- enableSubPackages:是否允许子包,是否让schema作为包的后缀
即targetPackage.schemaName.tableName -->
<property name="enableSubPackages" value="true" />
<!-- 从数据库返回的值是否清理前后的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- sqlMapGenerator Mapper映射文件的配置信息
targetProject:mapper映射文件生成的位置
targetPackage:生成mapper映射文件放在哪个包下-->
<sqlMapGenerator targetPackage="com.cskaoyan.mapper"
targetProject=".\src\main\resources">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="true" />
</sqlMapGenerator>
<!--
javaClientGenerator 生成 Model对象(JavaBean)和 mapper XML配置文件 对应的Dao代码
targetProject:mapper接口生成的位置
targetPackage:生成mapper接口放在哪个包下
ANNOTATEDMAPPER
XMLMAPPER
MIXEDMAPPER
-->
<javaClientGenerator type="XMLMAPPER"
targetPackage="com.cskaoyan.mapper"
targetProject=".\src\main\java">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="true" />
</javaClientGenerator>
使用mac的同学targetProject里面使用 /
<!--生成的JavaBean、接口和映射文件的名称-->
<table tableName="market_admin" domainObjectName="Admin"/>
如果要重新生成,建议先把已有的文件删除掉在重新生成 → 因为映射文件做的是增量更新 → 会导致映射文件中出现相同的id
生成类
配置 能够加载到配置文件的地址
//new File的时候 👉 加载的是working directory的相对目录
File configFile = new File("src/main/resources/generatorConfig.xml");
使用Mapper接口生成的方法
ByPrimaryKey
主要做的事情是生成条件:主键等于一个值的条件
比如
where id = #{id,jdbcType=INTEGER}
Selective
选择性的 → 传入的值不为null → if标签
-- 假设只有id、username、password不为null
-- 哪一列传入了值,则给它插入对应的值;如果没有传入值,相当于该列对应的值为null,则不插入对应的值
-- 数据库表的列可以设置默认值,如果你插入记录的时候,没有给这一列插入对应的值,会采用默认值
-- 如果你要给数据中的某一列插入默认值,你让其传入的这一列对应的参数为null
insert into market_admin (id,username,password) values (#{id,jdbcType=INTEGER},#{username,jdbcType=VARCHAR},#{password,jdbcType=VARCHAR})
<insert id="insertSelective" parameterType="com.cskaoyan.bean.Admin">
insert into market_admin
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="username != null">
username,
</if>
<if test="password != null">
password,
</if>
<if test="lastLoginIp != null">
last_login_ip,
</if>
<if test="lastLoginTime != null">
last_login_time,
</if>
<if test="avatar != null">
avatar,
</if>
<if test="addTime != null">
add_time,
</if>
<if test="updateTime != null">
update_time,
</if>
<if test="deleted != null">
deleted,
</if>
<if test="roleIds != null">
role_ids,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=INTEGER},
</if>
<if test="username != null">
#{username,jdbcType=VARCHAR},
</if>
<if test="password != null">
#{password,jdbcType=VARCHAR},
</if>
<if test="lastLoginIp != null">
#{lastLoginIp,jdbcType=VARCHAR},
</if>
<if test="lastLoginTime != null">
#{lastLoginTime,jdbcType=TIMESTAMP},
</if>
<if test="avatar != null">
#{avatar,jdbcType=VARCHAR},
</if>
<if test="addTime != null">
#{addTime,jdbcType=TIMESTAMP},
</if>
<if test="updateTime != null">
#{updateTime,jdbcType=TIMESTAMP},
</if>
<if test="deleted != null">
#{deleted,jdbcType=BIT},
</if>
<if test="roleIds != null">
#{roleIds,jdbcType=VARCHAR},
</if>
</trim>
</insert>
update使用selective可以避免其他不需要更新的列 被更新
ByExample
传入了一个参数Example,Example是通过逆向工程生成的。
构造单表的条件
设定排序
去重 distinct
<select id="selectByExample" parameterType="com.cskaoyan.bean.AdminExample" resultMap="BaseResultMap">
select
<!--判断Example中的boolean类型的distinct是否为true-->
<if test="distinct">
distinct
</if>
<include refid="Base_Column_List" />
from market_admin
<!--_parameter指的是当前的参数 → example对象本身-->
<if test="_parameter != null">
<!--引入sql片段*** 构造的是条件-->
<include refid="Example_Where_Clause" />
</if>
<!--判断example中的orderByClause是否为null-->
<if test="orderByClause != null">
order by ${orderByClause}
</if>
</select>
public Criteria andUsernameLike(String value) {
addCriterion("username like", value, "username");
return (Criteria) this;
}
public Criteria andUsernameBetween(String value1, String value2) {
addCriterion("username between", value1, value2, "username");
return (Criteria) this;
}
protected abstract static class GeneratedCriteria {
protected List<Criterion> criteria;
protected void addCriterion(String condition, Object value, String property) {
if (value == null) {
throw new RuntimeException("Value for " + property + " cannot be null");
}
criteria.add(new Criterion(condition, value));
}
}
<!--collection List<Criterion> -->
<foreach collection="criteria.criteria" item="criterion">
<choose>
<when test="criterion.noValue">
and ${criterion.condition}
</when>
<when test="criterion.singleValue">
and ${criterion.condition} #{criterion.value}
</when>
<when test="criterion.betweenValue">
and ${criterion.condition} #{criterion.value} and #{criterion.secondValue}
</when>
<when test="criterion.listValue">
and ${criterion.condition}
<foreach close=")" collection="criterion.value" item="listItem" open="(" separator=",">
#{listItem}
</foreach>
</when>
</choose>
</foreach>
注意事项
-
逆向工程生成的是文件 👉 文件可以自己修改
-
生成的内容不保证没有错误
- 列名出现sql的关键词,比如from、desc、order 👉 `from`,`desc`,`order`,注意是飘号(esc下面,1左边)不是单引号
- 会出现在逆向工程的Base_Column_List、update、insert语句、Example中的and方法
- SyntaxException 语法错误 👉 看控制台 👉 检查控制台中的sql语句
-
如果要重新生成,先把之前的内容删除掉(至少删除映射文件),增量更新导致出现重复id
-
不建议在已有的项目中使用逆向工程 👉 有可能导致已有的代码丢失
TypeHandler
类型处理器
前端响应的结果类型 → 和数据库里查询结果封装的类型不一致
mall_admin中的role_ids数据库中的类型varchar
而varchar类型的值 → String → Integer[]
输出映射:varchar → String → Integer[]
输入映射:Integer[] → String → varchar
TypeHandler中完成类型转换:String ↔ Integer[] 可以通过Json的工具类jackson
public interface TypeHandler<T> {
//输入映射过程 Integer[] → String
void setParameter(PreparedStatement var1, int var2, T var3, JdbcType var4) throws SQLException;
//输出映射过程 String → Integer[]
T getResult(ResultSet var1, String var2) throws SQLException;
T getResult(ResultSet var1, int var2) throws SQLException;
T getResult(CallableStatement var1, int var2) throws SQLException;
}
public class IntegerArrayTypeHandler implements TypeHandler<Integer[]> {
//jackson
ObjectMapper objectMapper = new ObjectMapper();
@Override
public void setParameter(PreparedStatement preparedStatement, int i, Integer[] integers, JdbcType jdbcType) throws SQLException {
//Integer[] → String
try {
String value = objectMapper.writeValueAsString(integers);
//给对应序号的占位符提供值
preparedStatement.setString(i, value);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
//String → Integer[]
@Override
public Integer[] getResult(ResultSet resultSet, String columnName) throws SQLException {
try {
//从结果集中根据列名获得对应类的查询结果
String result = resultSet.getString(columnName);
//把String类型的结果封装为参数(resultMap中的property属性对应的参数)需要的类型
Integer[] integers = objectMapper.readValue(result, Integer[].class);
return integers;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return new Integer[0];
}
}
配置typeHandler
如果没有配置的话,需要输入映射和输出映射过程单独来指定
配置的是可用的typeHandler都有谁,并且映射的类型是什么
typeHandler的包目录的配置
<typeHandlers> <package name="com.cskaoyan.typehandler"/> </typeHandlers>
springboot可以直接在配置文件中指定
mybatis: type-handlers-package: com.cskaoyan.typehandler
TypeHandler类上指明映射的类型
@MappedTypes(Integer[].class) @MappedJdbcTypes(JdbcType.VARCHAR) public class IntegerArrayTypeHandler implements TypeHandler<Integer[]>{}
@MappedTypes这里能写数组的情况不要写List,如果用List类型的识别会有问题
Invalid Binding Exception
Mapper接口和映射文件是对应起来
接口中的方法和标签中的id是对应起来
出现这个异常的场景:
- 映射文件没有编译进去
- 映射文件和接口不在同一级目录
- 名字没有对应起来
SyntaxException → 语法错误
前端也可以看控制台
视图页面没有解析,可以查看console
也可以看前端代码如何解析数据的 → vue、js
jackson
Date ↔ String
直接接收请求参数:@DateTimeFormat
Json日期:@JsonFormat(接收json日期,响应json日期)
日期的格式
jackson可以在配置文件中以jackson作为前缀去做相关配置
TypeHandler类上指明映射的类型
@MappedTypes(Integer[].class) @MappedJdbcTypes(JdbcType.VARCHAR) public class IntegerArrayTypeHandler implements TypeHandler<Integer[]>{}
@MappedTypes这里能写数组的情况不要写List,如果用List类型的识别会有问题
Invalid Binding Exception
Mapper接口和映射文件是对应起来
接口中的方法和标签中的id是对应起来
出现这个异常的场景:
- 映射文件没有编译进去
- 映射文件和接口不在同一级目录
- 名字没有对应起来
SyntaxException → 语法错误
前端也可以看控制台
视图页面没有解析,可以查看console
也可以看前端代码如何解析数据的 → vue、js
jackson
Date ↔ String
直接接收请求参数:@DateTimeFormat
Json日期:@JsonFormat(接收json日期,响应json日期)
日期的格式
jackson可以在配置文件中以jackson作为前缀去做相关配置
[外链图片转存中…(img-ifJJoOY3-1707112586992)]