功能实现代码
拦截器
- 拦截器逻辑
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
private RedisTemplate redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){
//1.获取token
String token = request.getHeader("token");
System.out.println("前端传过来的Token: " + token);
if (token!=null && !"".equals(token.trim())){//防止请求没有token,jwt
//解密
try {
PublicKey publicKey = RsaUtils.getPublicKey(JwtUtils.class.getClassLoader().getResource("auth_rsa.pub").getFile());
System.out.println("获取公钥类加载器: "+JwtUtils.class.getClassLoader());
System.out.println("公钥: "+publicKey);
// 解析出错了, 公钥和私钥不配对吗
Payload<LoginData> payload = JwtUtils.getInfoFromToken(token, publicKey, LoginData.class);
System.out.println("解析得到用户信息: "+ payload);
return true;//解密成功
} catch (Exception e) {
e.printStackTrace();
//解密失败抛异常
}
}
try {
//当前没有token,告诉前端 没有登录,不放行
//跳转到登录页面 - 后端跳不了,因为后端项目没有页面 - 放在前端跳转
//告诉浏览器我要给你响应一个json数据,编码集为utf-8
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println("{\"success\":false,\"message\":\"noLogin\"}");
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
}
- 配置拦截
@Configuration
public class MyWebConfig implements WebMvcConfigurer {
@Autowired
private LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
//拦截所有请求
.addPathPatterns("/**")
//放行跟登录的请求
.excludePathPatterns("/logininfo/login/**")
//放行跟注册有关的
.excludePathPatterns("/user/register/**", "/verifyCode/**")
.excludePathPatterns("/shop/settlement", "/fastDfs/**")
//放行swagger
.excludePathPatterns("/swagger-resources/**", "/webjars/**",
"/v2/**", "/swagger-ui.html/**")
//如果写了邮箱注册和激活还要放行
.excludePathPatterns("/shop/active/**", "/user/active/**");
}
}
注解
//四大元注解
@Target(ElementType.METHOD)//用在方法上
@Retention(RetentionPolicy.RUNTIME)//生命周期运行时
@Documented//文档可见
@Inherited //可以被继承
public @interface PreAuthorize {
//对应t_permission表中的sn
String sn();
//对应t_permission表中的name
String name();
}
全局异常
- 自定义业务异常
public class BusinessException extends RuntimeException {// 继承非受检异常, throw错误不需要向上抛出
public BusinessException() {
}
public BusinessException(String message) {
super(message);
}
}
- 全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {//执行顺序应该是先检查范围小的异常, 比如业务异常
// 全局异常处理
@ExceptionHandler(Exception.class)
public JSONResult globalException(Exception e) {
e.printStackTrace();
return JSONResult.error(ExceptionEnumType.SYSTEM_ERROR.toString());
}
@ExceptionHandler(BusinessException.class)
public JSONResult BusinessException(BusinessException e) {
e.printStackTrace();
// return JSONResult.error(ExceptionEnumType.BUSINESS_ERROR.toString());
return JSONResult.error(e.getMessage());// 将传给构造器的参数message传给前端,更灵活
}
@ExceptionHandler(IllegalArgumentException.class)
public JSONResult IllegalArgumentException(BusinessException e) {
e.printStackTrace();
return JSONResult.error(ExceptionEnumType.PARAM_ERROR.toString());
}
}
- 异常枚举类
// 异常枚举
public enum ExceptionEnumType {
// 参数错误
PARAM_ERROR("参数错误","10001"),
// 业务异常
BUSINESS_ERROR("业务异常","10002"),
// 系统异常
SYSTEM_ERROR("系统异常","10003"),
// 数据异常
DATA_ERROR("数据异常","10004");
private String message;
private String code;
ExceptionEnumType(String message, String code) {
this.message = message;
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
@Override
public String toString() {
return message + '[' + code + ']';
}
}
Mybatis分页
@Data
public class BaseQuery {//pageSize pageSize
//当前页
private Integer currentPage = 1;
//每一页显示的条数
private Integer pageSize = 5;
//keyword关键字
private String keyword;
//计算limit的第一个参数
public Integer getBegin(){
return (this.currentPage-1)*this.pageSize;
}
@Override
public String toString() {
return "BaseQuery{" +
"currentPage=" + currentPage +
", pageSize=" + pageSize +
", keyword='" + keyword + '\'' +
'}';
}
}
MybatisPlus分页
- 这是MybatisPlus方法分页
@Data
public class PageList<T> {
//条数
private Long total = 0L;
//列表
private List<T> rows = new ArrayList<>();
public PageList() {
}
public PageList(Long total, List<T> rows) {
this.total = total;
this.rows = rows;
}
}
- 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
- Controller方法
@RequestMapping(value = "/pagelist",method = RequestMethod.POST)
public JSONResult page(@RequestBody EmployeeQuery query){
Page<Employee> page = new Page<>(query.getPage(),query.getRows());//这是MybatisPlus方法提供的Page
page = employeeService.selectPage(page);
return JSONResult.success(new PageList<>(page.getTotal(),page.getRecords()));
}
工具类
返回json结果类
消息message和状态码code
//返回JSON结果
@Data
//建造者模式
//@Builder
public class JSONResult {
private boolean success = true;
private String message = "成功";
//错误码,用来描述错误类型 ,1000 表示么有错误
private String code = "1000";
//返回的数据
private Object data;
/**
* 创建当前实例
**/
public static JSONResult success() {
return new JSONResult();
}
/**
* 创建当前实例
**/
public static JSONResult success(Object obj) {
JSONResult instance = new JSONResult();
instance.setData(obj);
return instance;
}
public static JSONResult success(Object obj, String code) {
JSONResult instance = new JSONResult();
instance.setCode(code);
instance.setData(obj);
return instance;
}
/**
* 创建当前实例
**/
public static JSONResult error(String message, String code) {
JSONResult instance = new JSONResult();
instance.setMessage(message);
instance.setSuccess(false);
instance.setCode(code);
return instance;
}
public static JSONResult error() {
JSONResult jsonResult = new JSONResult();
jsonResult.setSuccess(false);
return jsonResult;
}
/**
* 创建当前实例
**/
public static JSONResult error(String message) {
return error(message, null);
}
}
链式调用
@Data
public class AjaxResult {
//接口状态(true:成功;false:失败)
private Boolean success = true;
//返回前端的提示信息(成功)
private String message = "操作成功";
//存储返回给前端的数据
private Object resultObj;
//无参构造
public AjaxResult(){}
//有参构造
public AjaxResult(Boolean success, String message) {
this.success = success;
this.message = message;
}
//链式语法改造
public static AjaxResult me(){
return new AjaxResult();
}
public AjaxResult setSuccess(Boolean success) {
this.success = success;
return this;
}
public AjaxResult setMessage(String message) {
this.message = message;
return this;
}
public AjaxResult setResultObj(Object resultObj) {
this.resultObj = resultObj;
return this;
}
}
纯配置
Swagger配置
- 配置类config
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
//对外暴露服务的包,以controller的方式暴露,所以就是controller的包.
.apis(RequestHandlerSelectors.basePackage("cn.tjw.ymcc.web.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("管理系统")
.description("管理系统接口文档说明")
.contact(new Contact("whale.chen", "", "[email protected]"))
.version("1.0")
.build();
}
}
- 配置需要的依赖
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
Redis重写序列化配置
- 配置类config
//缓存的配置
@Configuration
public class RedisConfig {
@Resource
private RedisConnectionFactory factory;
//使用JSON进行序列化
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
//JSON格式序列化
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
//key的序列化
redisTemplate.setKeySerializer(genericJackson2JsonRedisSerializer);
//value的序列化
redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
//hash结构key的虚拟化
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
//hash结构value的虚拟化
redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
return redisTemplate;
}
}
- 配置需要的依赖
<!--整合Redis , 底层可以用jedis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
- yml文件配置
spring:
redis:
database: 0
host: 127.0.0.1
port: 6379
password: 123456
jedis:
pool:
max-wait: 2000ms
min-idle: 2
max-idle: 8
MybatisPlus配置
- 配置类config
@Configuration
//mapper接口扫描
@MapperScan("cn.tjw.ymcc.mapper")
//事务管理
@EnableTransactionManagement
public class MybatisPlusConfig {
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
- yml文件配置
mybatis-plus:
mapper-locations: classpath:cn/tjw/ymcc/mapper/*Mapper.xml
Maven
父项目maven依赖配置模板
父项目只是统一管理依赖版本号—使用
标签管理 如果子项目需要用到某项依赖仍需导入, 但不需要配置版本号; 使用
<?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>cn.tjw</groupId>
<artifactId>SpringCloud</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>eureka-server</module>
<module>order-server</module>
<module>logistic-server</module>
</modules>
<properties>
<!-- 指定项目的编码和java版本-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!-- 有时可以配置使用 Java 11 语法来编译源码,但生成的字节码文件与 Java 8 兼容,可以在 Java 8 运行时环境中执行。-->
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
<mybatis.version>2.1.1</mybatis.version>
</properties>
<!--1.管理 SpringBoot的jar包-->
<!--SpringBoot-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
</parent>
<!--2. 统一管理相关依赖,供子项目直接引入使用-->
<dependencyManagement>
<!--
${spring-cloud.version} 在 properties指定
${mysql.version} 在SpringBoot2.2.5版本默认8.0.19
${mybatis.version} 在 properties指定
-->
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<!-- 解决每次刷新maven就改变编译版本的bug-->
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Mybatis
Mybatis配置支持*匹配扫描包
- 配置别名包(可不配)
/**
* Mybatis支持*匹配扫描包
*/
@Configuration
public class MyBatisConfig
{
@Autowired
private MybatisProperties mybatisProperties;
static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
// type-aliases-package: cn.tjw.*.domain,cn.tjw.*.query
public static String setTypeAliasesPackage(String typeAliasesPackage)
{
ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver();
MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);
List<String> allResult = new ArrayList<String>();
try
{
for (String aliasesPackage : typeAliasesPackage.split(","))
{
List<String> result = new ArrayList<String>();
//classpath*:cn/tjw/*/domain/**/*.class
aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+ ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN;
Resource[] resources = resolver.getResources(aliasesPackage);
if (resources != null && resources.length > 0)
{
MetadataReader metadataReader = null;
for (Resource resource : resources)
{
if (resource.isReadable())
{
metadataReader = metadataReaderFactory.getMetadataReader(resource);
try
{
result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName());
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}
}
}
if (result.size() > 0)
{
HashSet<String> hashResult = new HashSet<String>(result);
allResult.addAll(hashResult);
}
}
if (allResult.size() > 0)
{
typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0]));
}
else
{
throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包");
}
}
catch (IOException e)
{
e.printStackTrace();
}
return typeAliasesPackage;
}
public Resource[] resolveMapperLocations(String[] mapperLocations)
{
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
List<Resource> resources = new ArrayList<Resource>();
if (mapperLocations != null)
{
for (String mapperLocation : mapperLocations)
{
try
{
Resource[] mappers = resourceResolver.getResources(mapperLocation);
resources.addAll(Arrays.asList(mappers));
}
catch (IOException e)
{
// ignore
}
}
}
return resources.toArray(new Resource[resources.size()]);
}
//自配置SqlSessionFactory
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
{
String typeAliasesPackage = mybatisProperties.getTypeAliasesPackage();
String[] mapperLocations = mybatisProperties.getMapperLocations();
String configLocation = mybatisProperties.getConfigLocation();
org.apache.ibatis.session.Configuration configuration = mybatisProperties.getConfiguration();
typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
VFS.addImplClass(SpringBootVFS.class);
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
sessionFactory.setConfiguration(configuration);
Resource[] resources = resolveMapperLocations(mapperLocations);
if (resources!=null&&resources.length>0){
sessionFactory.setMapperLocations(resources);
}
if (StringUtils.hasLength(configLocation))
sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
return sessionFactory.getObject();
}
}
- 配置mybatis
mybatis:
configuration:
map-underscore-to-camel-case: true #开启驼峰字段转换,自动映射时将有下划线的字段的数据映射给驼峰字段
type-aliases-package: cn.tjw.*.domain,cn.tjw.*.query,cn.tjw.*.dto
Mapper.xml文件
注意
SQL错误首先检查一下几点:
- 是否开启别名包支持以及驼峰自动映射
- 是否需要自定义映射; 是否取别名; 是否检查为空
- 字段名是否正确, 包括是否开启驼峰命名; 是否数据库字段和实体类字段混淆; 是否存在该字段等;
- 语法是否正确 包括是否去空格trim; 是否少逗号; 保留字是否加反引号等; 加where 1=1衔接;
- 参数个数是否对应 包括传进来的接口参数个数; 可以尝试mapper接口加@Param注解;
mybatis:
configuration:
map-underscore-to-camel-case: true #开启驼峰字段转换,自动映射时将有下划线的字段的数据映射给驼峰字段
type-aliases-package: cn.tjw.*.domain,cn.tjw.*.query,cn.tjw.*.dto
insert模板
- 使用values可以插入多行数据, value只能插入一行
<insert id="add1" useGeneratedKeys="true" keyColumn="id" keyProperty="id" parameterType="Department">
insert into t_department(sn, name, dirPath, state, manager_id, parent_id)
VALUES (#{sn},#{name},#{dirPath},#{state},#{managerId},#{parentId})
</insert>
- if标签判空
<insert id="add2" useGeneratedKeys="true" keyColumn="id" keyProperty="id" parameterType="Department">
insert into t_department SET
<if test="sn != null">sn = #{sn}, </if>
<if test="name != null and name != ''">name = #{name}, </if>
<if test="dirPath != null and dirPath != ''">dirPath = #{dirPath}, </if>
<if test="state != null">state = #{state}, </if>
<if test="managerId != null">manager_id = #{managerId}, </if>
<if test="parentId != null">parent_id = #{parentId}
</if>
</insert>
- trim能够自动删掉最后的, suffixOverrides="," 不保留最后的逗号
<insert id="add3" useGeneratedKeys="true" keyColumn="id" keyProperty="id" parameterType="Department">
insert into t_department
<trim prefix="SET" suffixOverrides=",">
<if test="sn != null">
sn = #{sn},
</if>
<if test="name != null and name != ''">
name = #{name},
</if>
<if test="dirPath != null and dirPath != ''">
dirPath = #{dirPath},
</if>
<if test="state != null">
state = #{state},
</if>
<if test="managerId != null">
manager_id = #{managerId},
</if>
<if test="parentId != null">
parent_id = #{parentId}
</if>
</trim>
</insert>
update模板
- 第一种简写
<update id="update" parameterType="Department">
update t_department set
sn=#{sn}, name=#{name}, dirPath=#{dirPath}, state=#{state}, manager_id=#{managerId}, parent_id=#{parentId}
where id=#{id}
</update>
- 第二种 去掉有可能会有多余的,
<update id="update" parameterType="Department">
update t_department set
<if test="sn != null">sn=#{sn},</if>
<if test="name != null">name=#{name},</if>
<if test="dirPath != null">dirPath=#{dirPath},</if>
<if test="state != null">state=#{state},</if>
<if test="managerId != null">manager_id=#{managerId},</if>
<if test="parentId != null">parent_id=#{parentId}</if>
where id=#{id}
</update>
- 第三种 suffixOverrides=","—>表示去掉后面多余的,
<update id="update" parameterType="Department">
update t_department
<set>
<trim suffixOverrides=",">
<if test="sn != null">
sn = #{sn},
</if>
<if test="name != null">
name = #{name},
</if>
<if test="dirPath != null">
dirPath = #{dirPath},
</if>
<if test="state != null">
state = #{state},
</if>
<if test="managerId != null">
manager_id = #{managerId},
</if>
<if test="parentId != null">
parent_id = #{parentId}
</if>
</trim>
</set>
where id = #{id}
</update>
delete模板
- 第一种简写
<delete id="del">
delete from t_department where id=#{id}
</delete>
- 第二种
<delete id="del">
delete from t_department
<where>
<if test="id != null">
AND id = #{id}
</if>
<if test="name != null">
AND name = #{name}
</if>
<if test="sn != null">
AND sn = #{sn}
</if>
<!-- 添加其他条件 -->
</where>
</delete>
- 第三种trim去多余AND
<!-- prefixOverrides="AND" —> 去前面多余AND-->
<delete id="del">
delete from t_department
<where>
<trim prefix="AND" prefixOverrides="AND">
<if test="id != null">
AND id = #{id}
</if>
</trim>
</where>
</delete>
select模板
- 第一种简写
<select id="findOne" resultMap="DepartmentMap">
select * from t_department where id=#{id} and name=#{name}
</select>
- 第二种
<select id="findOne" resultMap="DepartmentMap">
select *
from t_department
<where>
<if test="id != null">
AND id = #{id}
</if>
<if test="name != null">
AND name = #{name}
</if>
<if test="sn != null">
AND sn = #{sn}
</if>
<!-- 继续添加其他条件 -->
</where>
</select>
- 第三种where 1 = 1
<select id="findOne" resultMap="DepartmentMap">
select *
from t_department
where 1 = 1
<if test="id != null">
AND id = #{id}
</if>
<if test="name != null">
AND name = #{name}
</if>
<if test="sn != null">
AND sn = #{sn}
</if>
<!-- 添加其他条件 -->
</select>
- 第四种 trim去多余的AND
<select id="findOne" resultMap="DepartmentMap">
select *
from t_department
<where>
<trim prefix="AND" prefixOverrides="AND">
<if test="id != null">
AND id = #{id}
</if>
<!-- 添加其他条件 -->
<!-- 注意:即使判空了, 接口只传一个参数就不能多写,否则会报参数找不到 -->
</trim>
</where>
</select>
批量操作
- 遍历数组
<delete id="patchDel">
delete from t_department where id in
<foreach collection="array" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</delete>
- 遍历list集合
<insert id="addBatch" parameterType="java.util.List">
insert into role_sources (rsid, rsdis, sid, roleid) values
<foreach collection="list" item="rs" separator=",">
(#{rs.rsid},
#{rs.rsdis},
#{rs.sid},
#{rs.roleid})
</foreach>
</insert>
- public List
selectAllUsers(@Param("ids") Integer[] ids);
<select id="selectAllUsers" parameterType="java.util.Array" >
select * from user where id in
<foreach collection="ids" open="(" close=")" separator="," item="item">
#{item,jdbcType=INTEGER}
</foreach>
</select>
自定义映射
<!--自定义映射-->
<resultMap id="DepartmentMap" type="cn.tjw.org.domain.Department">
<id column="id" property="id"></id>
<result column="sn" property="sn"></result>
<result column="name" property="name"></result>
<result column="dirPath" property="dirPath"></result>
<result column="state" property="state"></result>
<result column="manager_id" property="managerId"></result>
<result column="parent_id" property="parentId"></result>
<association property="manager" javaType="cn.itsource.org.domain.Employee">
<id column="eid" property="id"></id>
<result column="username" property="username"></result>
</association>
<association property="parent" javaType="cn.itsource.org.domain.Department">
<id column="pid" property="id"></id>
<result column="pname" property="name"></result>
</association>
</resultMap>
SQL抽取
<sql id="whereQuery">
<where>
<if test="keyword!=null and keyword!=''">
d.sn like concat('%',#{keyword},'%')
or
d.name like concat('%',#{keyword},'%')
</if>
</where>
</sql>
在需要的地方使用include引入
<include refid="whereQuery"></include>
微服务
使用的是第二代微服务 alibaba微服务框架
服务发现注册和配置中心
微服务远程配置
application.yml配置后加载, 会覆盖bootstrap.yml配置=>也就是application.yml优先级高, 所以说先拉取远程配置, 有需要改动的自己在application.yml里覆盖配置
- bootstrap.yml 指定远程哪个文件为项目配置, 拉取nacos远程配置文件
spring:
cloud:
nacos:
discovery: # 服务发现-指定nacos地址和命名空间
server-addr: localhost:8848 # 指定nacos注册中心地址
namespace: 8ac33b99-97e0-4bf4-9bb5-93b671a3bf4a
config: # 服务配置-指定nacos配置远程的yaml文件
server-addr: localhost:8848
prefix: service-gateway
file-extension: yaml
group: DEFAULT_GROUP
namespace: 8ac33b99-97e0-4bf4-9bb5-93b671a3bf4a # 命名空间
profiles:
active: dev # 激活开发环境
- 远程nacos配置yaml文件
# gateway配置 太多了
server:
port: 10010
spring:
application:
name: service-gateway #服务名
cloud: #注册到Nacos
nacos:
discovery:
server-addr: 127.0.0.1:8848
gateway:
discovery:
locator:
enabled: false #开放服务名访问方式
lower-case-service-id: true #服务名小写
routes: #路由配置
- id : application-user #指定服务名
uri: lb://service-user #去注册中心找这个服务名
predicates: #断言,匹配访问的路径
- Path=/ymcc/user/** #服务访问路径
filters:
- StripPrefix=2
- id: application-uaa #指定服务名
uri: lb://service-uaa #去注册中心找这个服务名
predicates: #断言,匹配访问的路径
- Path=/ymcc/uaa/** #服务访问路径
filters:
- StripPrefix=2
- id: application-course #指定服务名
uri: lb://service-course #去注册中心找这个服务名
predicates: #断言,匹配访问的路径
- Path=/ymcc/course/** #服务访问路径
filters:
- StripPrefix=2
- id: application-system #指定服务名
uri: lb://service-system #去注册中心找这个服务名
predicates: #断言,匹配访问的路径
- Path=/ymcc/system/** #服务访问路径
filters:
- StripPrefix=2
- id: application-search #指定服务名
uri: lb://service-search #去注册中心找这个服务名
predicates: #断言,匹配访问的路径
- Path=/ymcc/search/** #服务访问路径
filters:
- StripPrefix=2
- id: application-pay #指定服务名
uri: lb://service-pay #去注册中心找这个服务名
predicates: #断言,匹配访问的路径
- Path=/ymcc/pay/** #服务访问路径
filters:
- StripPrefix=2
- id: application-order #指定服务名
uri: lb://service-order #去注册中心找这个服务名
predicates: #断言,匹配访问的路径
- Path=/ymcc/order/** #服务访问路径
filters:
- StripPrefix=2
- id: application-media #指定服务名
uri: lb://service-media #去注册中心找这个服务名
predicates: #断言,匹配访问的路径
- Path=/ymcc/media/** #服务访问路径
filters:
- StripPrefix=2
- id: application-kill #指定服务名
uri: lb://service-kill #去注册中心找这个服务名
predicates: #断言,匹配访问的路径
- Path=/ymcc/kill/** #服务访问路径
filters:
- StripPrefix=2
- id: application-common #指定服务名
uri: lb://service-common #去注册中心找这个服务名
predicates: #断言,匹配访问的路径
- Path=/ymcc/common/** #服务访问路径
filters:
- StripPrefix=2
globalcors: #跨域配置
cors-configurations:
'[/**]':
allowedOrigins: "*"
allow-credentials: true
allowed-headers: "*"
allowedMethods:
- GET
- POST
- DELETE
- PUT
- PATCH
- OPTIONS
- HEAD
- CONNECT
- TRACE
#允许Bean覆盖
main:
allow-bean-definition-overriding: true
- application.yml配置, 可以覆盖远程配置
server:
port: 10001
spring:
application:
name: service-system # 应用名称
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
namespace: 8ac33b99-97e0-4bf4-9bb5-93b671a3bf4a
datasource:
url: jdbc:mysql:///ymcc-system?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
main:
allow-bean-definition-overriding: true # 允许Bean覆盖
mybatis-plus:
mapper-locations: classpath:cn/tjw/ymcc/mapper/*Mapper.xml
前端Vue
Vue
级联选择器
<!-- Cascader 级联选择器
:options="options" 级联选择器绑定的集合数据
-->
<el-form-item label="上级部门" prop="parentId">
<el-cascader v-model="saveForm.parentId"
:options="deptTree"
:props="{
checkStrictly: true,
value: 'id',//传给后端的参数
label: 'name', //前端回显的内容
}"
clearable>
</el-cascader>
</el-form-item>
选择器
<!--
el-select 下拉选
v-model="saveForm.managerId" 这个绑定,回显的时候,就知道是选择的那一个选项
el-option 选项
v-for 遍历
:label="item.username" 选中后选项框中 回显的内容
:value="item.id" 选中后,传递给后端的内容
-->
<el-form-item label="部门管理" prop="managerId">
<el-select v-model="saveForm.managerId" placeholder="请选择">
<el-option
v-for="item in managers"
:key="item.id"
:label="item.username"
:value="item.id">
<span style="float: left">{{ item.username }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ item.phone }}</span>
</el-option>
</el-select>
</el-form-item>
switch
<!-- <template scope="scope">
<span v-if="scope.row.state==1" style="color: green">上架</span>
<span v-else style="color: red">下架</span>
</template>-->
<el-table-column prop="state" label="状态" width="50">
<template scope="scope">
<el-switch
v-model="scope.row.state===1" @change="stateChange"
active-text="上架" >
</el-switch>
</template>
</el-table-column>
分页
<!--工具条-->
<el-col :span="24" class="toolbar">
<el-button type="danger" @click="batchRemove" :disabled="this.sels.length===0" v-perm="'pet:patchDel'">批量删除</el-button>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[5, 10, 20, 50]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
style="float:right;">
</el-pagination>
</el-col>
状态
<el-table-column prop="state" label="部门状态" width="160">
<template scope="scope">
<span v-if="scope.row.state==1" style="color: #13ce66">启用</span>
<span v-else-if="scope.row.state==0" style="color: #ee0a0a">禁用</span>
</template>
</el-table-column>
标签:return,String,模版,代码,id,new,public,name
From: https://www.cnblogs.com/code-jia/p/18070627