- 1.1 pom:父项目
- 1.2 war:发布的子项目
- 1.3 jar:不发布的工具项目
war 包依赖 jar 包,war 包不依赖 war 包
在 war 包的 pom.xml 的 dependencies 中
<!--依赖 shop-pojo -->
<dependency>
<groupId>com.qf.nice</groupId>
<artifactId>shop-pojo</artifactId>//jar包项目名
<version>1.0.0-SNAPSHOT</version>
</dependency>
3.1 在 properties 标签中添加自定义标签:
<junit-version>4.11</junit-version>
<serlvet-version>4.0.1</serlvet-version>
<mysql-version>5.1.6</mysql-version>
3.2 在对应的坐标中引用版本号
<version>${junit-version}</version>
4.1 File -- Project Structure
4.2 Artifacts -- "+" -- JAR -- From modules with ....
4.3 勾选 Include in project build
4.4 回到主页面 Build -- Build Artifacts
mvn install:install-file -Dfile=jar包位置 -DgroupId=组织名 -DartifactId=项目名 -Dversion=版本号 -Dpackaging=jar
mvn install:install-file -Dfile=D:\Software\java-jar\DBManger.jar -DgroupId=com.qf.hao.utils -DartifactId=DBManager -Dversion=1.0.0 -Dpackaging=jar
关于Ioc介绍
- 1.1 导入 Spring 容器的坐标
- 1.2 创建 spring-context.xml IOC的配置文件
- 1.3 加载配置文件创建 Spring 容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context.xml");
- 1.4 从容器中获取指定的对象
ClassDao classDao = (ClassDao) ctx.getBean("classDao");
//1、关于配置文件
<!-- 开启扫描,扫描有注解的包,让注解生效 -->
<context:component-scan base-package="com.qf.ran.controller"/>
<context:component-scan base-package="com.qf.ran.service.impl"/>
<context:component-scan base-package="com.qf.ran.dao.impl"/>
//2、关于部分注解
/**
* @author Ran
* @since JDK 1.8
*/
/*依赖*/
//@Component
@Controller
public class StudentController {
/*对象注入*/
@Autowired
StudentService studentService;
public void setStudentService(StudentService studentService) {
this.studentService = studentService;
}
public void method(){
System.out.println("Controller:"+studentService.method1());
}
}
1.添加 xml 配置文件开启扫描支持注解,base-package 值为注解所在的包
<context:component-scan base-package="com.qf.ran.controller"/>
2.添加依赖注解
@Component -- 把对象创建的控制权交给 Spring 容器(支持所有的类)
@Controller -- 支持控制成的注解
@Service -- 支持业务逻辑层的注解
@Repository -- 支持持久层的注解
3.添加注入注解
@Autowired -- 默认使用类型查找对象
默认选项为 true ,设置为 false 代表注入的对象可以为 null
在多线程中是不安全的
如果出现菱形依赖问题
可以通过 Autowired 修饰有参构造方法来解决依赖问题
先创建对象再注入属性对象
@Resources -- 默认根据 name 在容器中查找对象,没有 name 则根据类型查找对象
不允许对象为 null,线程安全
关于AOP介绍
1.业务划分:
主业务:
转账、充值
系统级业务:
事务控制、日志控制
2.静态代理:
优势:把主业务和系统级业务划分开
劣势:每个业务对象都需要一个代理类,会造成类的冗余
3.动态代理:
优势:每一个业务对象都可以使用同一个代理,减少类的冗余
劣势:产生对象的冗余,占用内存空间,修改了源代码
4.SpringAOP:面向切面编程 -- 基于XML配置
4.1 引入jar包
//注意这里没有显示版本号,是要导入有版本号才行
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
4.2 添加增强类 TransactionAdvice ,增强类中定义增强方法
4.3 添加XML配置文件 Spring-AOP.xml
前置增强
后置增强
环绕增强
异常处理增强
方法返回增强
5.SpringAOP:面向切面编程 -- 基于注解
5.1 引入 jar 包
5.2 创建切面类,并使用注解 @Component @Aspect
5.3 定义切点的方法,并添加注解
@Pointcut("execution(* com.qf.ran.service.impl.*ServiceImpl.pay(..))")
5.4 编写增强方法并添加对应的注解
5.5 在Spring配置文件中添加支持 AOP 注解的配置
<aop:aspectj-autoproxy/>
1、plign文件找不到解决办法
2、导包包已经下载好但是还是报错:idea的seting中勾选dubug …Maven
3、初始化异常:将juit测试包升级
//1、配置文件配置
<!-- 开启扫描,支持IOC注解 -->
<context:component-scan base-package="com.qf.ran"/>
<!--开启AOP注解支持(支持JDK动态代理)-->
<aop:aspectj-autoproxy/>
<!--开启AOP注解支持(proxy-target-class 设置为 true 代表使用cglib代理)-->
<!--<aop:aspectj-autoproxy proxy-target-class="true"/>-->
//2、关于代理类
*/
@Component
/*代表切面类*/
@Aspect
public class TransactionAdvice {
//定义切点
@Pointcut("execution(* com.qf.ran.service.impl.*ServiceImpl.pay(..))")//那些类需要增强写入
public void transactionPC(){
}
//前置增强
@Before("TransactionAdvice.transactionPC()")
public void before(){
System.out.println("前置增强(注解)");
}
//后置增强
@After("TransactionAdvice.transactionPC()")
public void after(){
System.out.println("后置增强(注解)");
}
//后置增强(异常出现后增强)
@AfterThrowing("TransactionAdvice.transactionPC()")
public void afterThrowing(){
System.out.println("异常增强(注解)");
}
//后置增强(方法返回结果后增强)
@AfterReturning("TransactionAdvice.transactionPC()")
public void afterReturning(){
System.out.println("返回结果后");
}
//环绕增强
@Around("TransactionAdvice.transactionPC()")
public Object around(ProceedingJoinPoint point) throws Throwable {
System.out.println("环绕前(注解)");
Object proceed = point.proceed();
System.out.println("环绕后(注解)");
return proceed;
}
}
//3、关于测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:Spring-context.xml"})//加载配置文件
public class UserControllerTest {
@Autowired
private UserController userController;
@Test
public void testTransferAccounts(){
userController.transferAccounts();
}
}
spring的介绍
1.1 导入 SpringMVC 的jar包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${springmvc-version}</version>
</dependency>
1.2 添加 Spring 的配置文件
1.2.1 开启 Spring 扫描
1.2.2 开启 SpringMVC 的注解支持 -- 注意约束
1.3 配置 web.xml 文件
1.3.1 配置编码过滤器,初始化参数指定编码格式为UTF-8
1.3.2 配置 DispatcherServlet 分发器,初始化参数加载 Spring 配置文件
1.3.3 配置 html 请求的默认访问
1.4 创建 Controller 层的类,添加注解@Controller @RequestMapping("/请求路径")
1.5 添加对应的方法并使用注解@RequestMapping("/请求路径")
2.1 添加 jar 包(fastjson、jackson)
2.2 Spring 配置文件添加消息转换器
2.3 前端发送ajax请求
2.4 添加 RespBean 类
2.5 Controller 层类方法添加注解 @ResponseBody (告诉Spring容器,返回的对象需要经过消息转换器转换成json 格式数据)
//xml文件
<!--开启 Spring 的扫描-->
<context:component-scan base-package="com.qf.ran"/>
<!--开启 SpringMVC 的注解支持-->
<mvc:annotation-driven/>
<!--消息转换器配置 FastJson-->
<!--把响应对象转换成json格式对象-->
<mvc:annotation-driven>
<mvc:message-converters register-defaults="false">
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=utf-8</value>
<value>application/json;charset=utf-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
//2、前端控制器
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--1.配置编码过滤器-->
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!--初始化-->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*
dispatcherServlet
org.springframework.web.servlet.DispatcherServlet
contextConfigLocation
classpath:spring-mvc.xml
dispatcherServlet
/
default
*.html
default
*.js
//3、导jar包
org.springframework
spring-webmvc
${springmvc-version}
com.alibaba
fastjson
1.2.73
//部分注释
/**
* @author Ran
* @since JDK 1.8
*/
@Controller
/*请求的映射路径*/
@RequestMapping("/User")
public class UserController {
@Autowired
private UserService userService;
/* @RequestMapping("/login")
*//*响应对象为json格式数据*//*
@ResponseBody
public RespBean login(String username,String password){
System.out.println("username:"+username);
System.out.println("password:"+password);
RespBean respBean = userService.login(username, password);
return respBean;
}*/
@RequestMapping("/login")
/*响应对象为json格式数据*/
@ResponseBody
public RespBean login(User user){
System.out.println("user的username:"+user.getUsername());
System.out.println("user的password:"+user.getPassword());
RespBean respBean = userService.login(user.getUsername(), user.getPassword());
return respBean;
}
@RequestMapping("/register")
public void register(){
System.out.println("注册方法");
}
}
DTO等详解
:@RestController注解相当于@ResponseBody + @Controller合在一起的作用
@ResponseBody的作用其实是将java对象转为json格式的数据。
@RequestMapping 来映射请求,也就是通过它来指定控制器可以处理哪些URL请求,相当于Servlet中在web.xml中配置
* PO:Persistent Object 持久对象 -- 与数据库的字段一致对象
* BO:Business Object 业务对象 -- 把业务逻辑需要的属性封装成一个对象
* VO:Value/View Object 值对象/视图对象 -- 抽象出的业务对象,主要对应页面显示的对象
* DTO:Data Transfer Object 数据传输对象 -- 在进行跨域或者远程传输时使用的对象
Responsebody
SpringMvc生命周期
/*
.1 RequestMapping
1.1.1 value -- 请求映射路径
1.1.2 method -- 指定提交方式
1.1.3 params -- 约束请求提交的参数
1.2 指定提交方式的映射注解
GetMapping、PostMapping...
1.3 RestController = Controller + ResponseBody
把控制层交由 Spring 创建对象并把当前对象中所有方法返回值指定转换为 json 格式数据
*/
//在类中添加注解,所有的方法都以json格式的对象方法
@GetMapping("/login")
public RespBean login(User user){
System.out.println("user的username:"+user.getUsername());
System.out.println("user的password:"+user.getPassword());
RespBean respBean = userService.login(user.getUsername(), user.getPassword());
return respBean;
}
//提交方式只能是get请求
@GetMapping("/login")
@ResponseBody
public RespBean login(User user){
System.out.println("user的username:"+user.getUsername());
System.out.println("user的password:"+user.getPassword());
RespBean respBean = userService.login(user.getUsername(), user.getPassword());
return respBean;
}*/
把控制层交由 Spring 创建对象并把当前对象中所有方法返回值指定转换为 json 格式数据
// 提交方式: GET:获取信息 POST:更新操作 PUT:新增操作 DELETE:删除操作
//代表提交方式只能是GET或者POST请求
@RequestMapping(value = "/login",method= {RequestMethod.GET,RequestMethod.POST})
@ResponseBody
public RespBean login(User user){
System.out.println("user的username:"+user.getUsername());
System.out.println("user的password:"+user.getPassword());
RespBean respBean = userService.login(user.getUsername(), user.getPassword());
return respBean;
}
<!--定义对象json装换器-->
<mvc:annotation-driven>
<mvc:message-converters>
<ref bean="stringHttpMessageConverter"/>
<ref bean="mappingJackson2HttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="stringHttpMessageConverter"
class="org.springframework.http.converter.StringHttpMessageConverter"/>
<!--解决IE浏览器json文件下载和json数据中文乱码的问题-->
<bean id="mappingJackson2HttpMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger-version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
/**
* @author Ran
* @since JDK 1.8
*/
/*代表当前类为配置文件类*/
@Configuration
@EnableSwagger2
/*扫描包 支持Swagger注解*/
@ComponentScan("com.qf.ran")
public class SwaggerConfiguration {
/*需要创建的对象*/
@Bean
public Docket createAPI() {
return new Docket(DocumentationType.SWAGGER_2)
.forCodeGeneration(true)
.select()
.apis(RequestHandlerSelectors.any())
//过滤生成链接
.paths(PathSelectors.any())
.build()
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
Contact contact = new Contact("Ran", "http://baidu.com"
, "[email protected]");
ApiInfo apiInfo = new ApiInfoBuilder()
.license("Apache License Version 2.0")
.title("Swagger 集成测试")
.description("Swagger API Teste")
.contact(contact)
.version("1.0")
.build();
return apiInfo;
}
}
<!--3.默认访问-->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
<mvc:resources mapping="swagger-ui.html" location="classpath:/META-INF/resources"/>
<mvc:resources mapping="/webjars/**" location="classpath:/META-INF/resources/webjars"/>
@Api(tags="用户模块") -- 模块注解
@ApiOperation("登录功能") -- 方法注解
@ApiModel -- 实体类注解
@ApiModelProperty(value = "状态值") -- 实体类属性注解
@Api(tags="用户模块")
@RestController
@RequestMapping("/User")
public class UserController {
@Autowired
private UserService userService;
@ApiOperation("登录功能")
@GetMapping(value = "/login")
public RespBean login(User user){
System.out.println("user的username:"+user.getUsername());
System.out.println("user的password:"+user.getPassword());
RespBean respBean = userService.login(user.getUsername(), user.getPassword());
return respBean;
}
@ApiOperation("注册功能")
@RequestMapping("/register")
public void register(){
System.out.println("注册方法");
}
}
@ControllerAdvice
@ResponseBody
public class HandlerException {
//异常处理,value = AccountException.class 代表只处理 AccountException 异常
@ExceptionHandler(value = AccountException.class)
public RespBean handlerException(AccountException e){
//e.getMessage() 获取异常信息
return RespBean.respError(e.getMessage());
}
/*处理所有的异常
@ExceptionHandler
public RespBean handlerException(Exception e){
}*/
}
/**
* @author Ran
* @since JDK 1.8
*
* 登录拦截器
*/
public class LoginInterceptor implements HandlerInterceptor {
//拦截方法 -- true为放行,false为拦截
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
Integer id = (Integer)request.getSession().getAttribute("id");
if(id == null){
throw new LoginException("用户未登录");
}
return true;
}
}
<!--拦截器栈配置-->
<mvc:interceptors>
<!--配置登录拦截器-->
<mvc:interceptor>
<!--需要拦截的请求-->
<!--
/* 代表只能拦截 /SpringMVC-interceptor/User
/** 代表能拦截 /SpringMVC-interceptor/User/login
-->
<!--文件上传 start-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!--文件上传 end-->
<!--文件上传配置-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--文件上传大小限制-->
<property name="maxUploadSize" value="104857600"/>
<!--文件上传的编码-->
<property name="defaultEncoding" value="UTF-8"/>
</bean>
**
* @author Ran
* @since JDK 1.8
*
* 文件上传模块
*/
@Api(tags = "文件上传模块")
@RestController
@RequestMapping("/file")
public class FileUploadController {
@ApiOperation("文件上传")
@PostMapping(value = "/upload",consumes = "multipart/*",
headers = "content-type=multipart/form-data")
public RespBean upload(@ApiParam(value = "文件") MultipartFile file, HttpServletRequest request, HttpServletResponse response){
//1\获取 img 路径并创建目录
String realPath = request.getServletContext().getRealPath("/asserts/img");
//解决重名
//获取文件名
String fileName = file.getOriginalFilename();
fileName = UUID.randomUUID().toString() +"_"+fileName;
//存储文件到服务器
try {
file.transferTo(new File(realPath,fileName));
} catch (IOException e) {
e.printStackTrace();
}
return RespBean.respSuccess("文件上传成功");
}
}
lamba表达式错误
打包遇到错误
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--Spring start-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!--Spring end-->
<!--druid start -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.23</version>
</dependency>
<!--druid end -->
<!-- mysql start-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-version}</version>
</dependency>
<!-- mysql end-->
<!--mybatis start-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--mybatis end-->
<!--lombok start-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok-version}</version>
</dependency>
<!--lombok end-->
<!--测试类加载配置文件 start-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
<!--测试类加载配置文件 end-->
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.connectionURL=jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8
jdbc.username=root
jdbc.password=root
# JDBC Pool
jdbc.pool.init=1
jdbc.pool.minIdle=3
jdbc.pool.maxActive=20
# JDBC Test
jdbc.testSql=SELECT 'x' FROM DUAL
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 全局参数 -->
<settings>
<!-- 打印 SQL 语句 -->
<setting name="logImpl" value="STDOUT_LOGGING" />
<!-- 使全局的映射器启用或禁用缓存。 -->
<setting name="cacheEnabled" value="false"/>
<!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载。 -->
<setting name="aggressiveLazyLoading" value="true"/>
<!-- 是否允许单条 SQL 返回多个数据集 (取决于驱动的兼容性) default:true -->
<setting name="multipleResultSetsEnabled" value="true"/>
<!-- 是否可以使用列的别名 (取决于驱动的兼容性) default:true -->
<setting name="useColumnLabel" value="true"/>
<!-- 允许 JDBC 生成主键。需要驱动器支持。如果设为了 true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行。 default:false -->
<setting name="useGeneratedKeys" value="false"/>
<!-- 指定 MyBatis 如何自动映射 数据基表的列 NONE:不映射 PARTIAL:部分 FULL:全部 -->
<setting name="autoMappingBehavior" value="PARTIAL"/>
<!-- 这是默认的执行类型 (SIMPLE: 简单; REUSE: 执行器可能重复使用prepared statements语句;BATCH: 执行器可以重复执行语句和批量更新) -->
<setting name="defaultExecutorType" value="SIMPLE"/>
<!-- 使用驼峰命名法转换字段。 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 设置本地缓存范围 session:就会有数据的共享 statement:语句范围 (这样就不会有数据的共享 ) defalut:session -->
<setting name="localCacheScope" value="SESSION"/>
<!-- 设置 JDBC 类型为空时,某些驱动程序 要指定值, default:OTHER,插入空值时不需要指定类型 -->
<setting name="jdbcTypeForNull" value="NULL"/>
</settings>
</configuration>
Spring-context.xml Spring配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--开启 Spring 扫描-->
<context:component-scan base-package="com.qf.ran"/>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--加载jdbc连接-->
<context:property-placeholder ignore-unresolvable="true" location="classpath:jdbc.properties"/>
<!-- 扫描 Mapper -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.qf.ran.dao"/>
</bean>
<!-- 配置 SqlSession -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--连接数据源-->
<property name="dataSource" ref="dataSource"/>
<!-- 用于配置对应实体类所在的包,多个 package 之间可以用 ',' 号分割 -->
<!--<property name="typeAliasesPackage" value="cn.qf.spring.mybatis.entity"/>-->
<!-- 用于配置对象关系映射配置文件所在目录 -->
<property name="mapperLocations" value="classpath:/mapper/**/*.xml"/>
<property name="configLocation" value="classpath:/MyBatis-config.xml"></property>
</bean>
<!--数据源配置,使用 druid 数据库连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass -->
<property name="driverClassName" value="${jdbc.driverClass}"/>
<!-- 基本属性 url、user、password -->
<property name="url" value="${jdbc.connectionURL}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!-- 配置初始化大小、最小、最大 -->
<property name="initialSize" value="${jdbc.pool.init}"/>
<property name="minIdle" value="${jdbc.pool.minIdle}"/>
<property name="maxActive" value="${jdbc.pool.maxActive}"/>
<!-- 配置获取连接等待超时的时间 -->
<property name="maxWait" value="60000"/>
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000"/>
<property name="validationQuery" value="${jdbc.testSql}"/>
<property name="testWhileIdle" value="true"/>
<property name="testOnBorrow" value="false"/>
<property name="testOnReturn" value="false"/>
<!-- 配置监控统计拦截的filters -->
<property name="filters" value="stat"/>
</bean>
</beans>
<servlet>
<servlet-name>DruidStatView</servlet-name>
<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DruidStatView</servlet-name>
<url-pattern>/druid/*
<sql id=""> 字段名的抽取,使用<include refid="">
<if> 判断赋值给字段的参数是否为 null ,不为 null 则进行填充
<where> 代替 where 关键词,自动省略 where 后面的 or 或者 and
<foreach> 遍历
<set> 代替 set 关键词,自动省略","
<trim> 自定义标签
<?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.qf.ran.dao.UserMapper">
<!--id 属性对应方法名-->
<!--<insert id="addUser">
insert into user(username,password) values(#{username},#{password});
</insert>-->
<!--
主键返回
sql 语句执行完后返回生成主键,对象的 id 属性接收 id 值
-->
<insert id="addUser" useGeneratedKeys="true" keyProperty="id">
insert into user(username,password) values(#{username},#{password});
</insert>
<!--测试 @Param 修饰对象-->
<insert id="method">
insert into user(username,password) values(#{user.username},#{user.password});
</insert>
<delete id="deleteUserById">
delete from user where id = #{id};
</delete>
<update id="updateUserById">
update
user
<set>
<if test="username != null and username != ''">
username = #{username},
</if>
<if test="password != null and password != ''">
password = #{password},
</if>
<if test="sex != null and sex != ''">
sex = #{sex}
</if>
</set>
where
id= #{id};
</update>
<!--字段抽取封装-->
<sql id="user_column">
id,username,password,sex
</sql>
<!--
trim 自定义标签
prefix 属性值为添加的前缀
prefixOverrides 每个 if 语句允许添加指定的关键字,根据需求删除关键字
-->
<select id="selectUser" resultType="User">
select
<include refid="user_column"/>
from
user
<trim prefix="where" prefixOverrides="and|or">
<if test="id != null and id != ''">
and id = #{id}
</if>
<if test="username != null and username != ''">
and username = #{username}
</if>
<if test="sex != null and sex != ''">
or sex = #{sex}
</if>
</trim>
</select>
<!--根据对象的属性进行查询-->
<!-- <include refid="user_column"/> 导入对应的字段数据 -->
<!--使用 where 标签会自动删除不需要的 and 或者 or-->
<!--<select id="selectUser" resultType="User">
select
<include refid="user_column"/>
from
user
<where>
<if test="id != null and id != ''">
and id = #{id}
</if>
<if test="username != null and username != ''">
and username = #{username}
</if>
<if test="sex != null and sex != ''">
and sex = #{sex}
</if>
</where>
</select>-->
<!-- resultType 返回值类型 -->
<!-- <select id="selectUserById" resultType="com.qf.ran.entity.User">
select id,username,password from user where id = #{id};
</select>-->
<select id="getList" resultType="User">
select
<include refid="user_column"/>
from
user;
</select>
<!-- 根据 id 集合查询多个对象信息-->
<!-- collection 对应方法中的集合参数 -->
<select id="selectUserListByIds" resultType="User">
select
<include refid="user_column"/>
from
user
where
id
in
<foreach collection="list" open="(" separator="," close=")" item="id">
#{id}
</foreach>
</select>
</mapper>
在这里插入代码片
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 指向需要实现的接口路径-->
<mapper namespace="com.qf.ran.dao.UserMapper">
<!--id 属性对应方法名-->
<!--<insert id="addUser">
insert into user(username,password) values(#{username},#{password});
</insert>-->
<!--
主键返回
sql 语句执行完后返回生成主键,对象的 id 属性接收 id 值
-->
<insert id="addUser" useGeneratedKeys="true" keyProperty="id">
insert into user(username,password) values(#{username},#{password});
</insert>
<!--测试 @Param 修饰对象-->
<insert id="method">
insert into user(username,password) values(#{user.username},#{user.password});
</insert>
<delete id="deleteUserById">
delete from user where id = #{id};
</delete>
<update id="updateUserById">
update
user
<set>
<if test="username != null and username != ''">
username = #{username},
</if>
<if test="password != null and password != ''">
password = #{password},
</if>
<if test="sex != null and sex != ''">
sex = #{sex}
</if>
</set>
where
id= #{id};
</update>
<!--字段抽取封装-->
<sql id="user_column">
id,username,password,sex
</sql>
<!--
trim 自定义标签
prefix 属性值为添加的前缀
prefixOverrides 每个 if 语句允许添加指定的关键字,根据需求删除关键字
-->
<select id="selectUser" resultType="User">
select
<include refid="user_column"/>
from
user
<trim prefix="where" prefixOverrides="and|or">
<if test="id != null and id != ''">
and id = #{id}
</if>
<if test="username != null and username != ''">
and username = #{username}
</if>
<if test="sex != null and sex != ''">
or sex = #{sex}
</if>
</trim>
</select>
<!--根据对象的属性进行查询-->
<!-- <include refid="user_column"/> 导入对应的字段数据 -->
<!--使用 where 标签会自动删除不需要的 and 或者 or-->
<!--<select id="selectUser" resultType="User">
select
<include refid="user_column"/>
from
user
<where>
<if test="id != null and id != ''">
and id = #{id}
</if>
<if test="username != null and username != ''">
and username = #{username}
</if>
<if test="sex != null and sex != ''">
and sex = #{sex}
</if>
</where>
</select>-->
<!-- resultType 返回值类型 -->
<!-- <select id="selectUserById" resultType="com.qf.ran.entity.User">
select id,username,password from user where id = #{id};
</select>-->
<select id="getList" resultType="User">
select
<include refid="user_column"/>
from
user;
</select>
<!-- 根据 id 集合查询多个对象信息-->
<!-- collection 对应方法中的集合参数 -->
<select id="selectUserListByIds" resultType="User">
select
<include refid="user_column"/>
from
user
where
id
in
<foreach collection="list" open="(" separator="," close=")" item="id">
#{id}
</foreach>
</select>
</mapper>
<!--事务处理器容器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource"/>
</bean>
<!--开启事务注解支持-->
<tx:annotation-driven transaction-manager="transactionManager"/>
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
/*开启一级缓存*/
// /*@Transactional(readOnly = true)*/
public User selectUser(User user){
userMapper.selectUser(user);
userMapper.selectUser(user);
userMapper.selectUser(user);
userMapper.selectUser(user);
userMapper.selectUser(user);
return null;
}
}
<!-- 使全局的映射器启用或禁用二级缓存。 -->
<setting name="cacheEnabled" value="true"/>
<?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.qf.ran.dao.UserMapper">
<!-- 开启当前namespace 的二级缓存-->
<cache/>
@Transactional(readOnly = true) 开启以及缓存
1、idea控制台中文乱码
<spring.version>5.2.9.RELEASE</spring.version>
<!-- Logback依赖,还会传递 slf4j 和 logback-core -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
//日志对象
private Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);
public User selectUserByUserId(Long id) {
//开发阶段
logger.debug("debug:"+id);
//追踪正常状态信息
logger.info("info:"+id);
try{
if(id == 11L){
//当系统出现不合理的情况但是不影响程序的运行
logger.warn("warn:用户id不存在,查询失败");
}
if(id == 100L){
throw new RuntimeException("异常说明:连接数据库失败");
}
}catch (RuntimeException e){
//系统级错误,导致程序无法正常运行
logger.error("error:"+e.getMessage());
}
return null;
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。
默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="60 seconds" debug="true">
<!-- 定义变量,可通过 ${log.path}和${CONSOLE_LOG_PATTERN} 得到变量值 -->
<!-- 指定日记保存目录 -->
<property name="log.path" value="D:/log"/>
<!-- 日志输出格式规定 -->
<property name="CONSOLE_LOG_PATTERN"
value="%d{yyyy-MM-dd HH:mm:ss.SSS} |-[%-5p] in %logger.%M[line-%L] -%m%n"/>
<!-- 输出到控制台 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!-- Threshold=即最低日志级别,此appender输出大于等于对应级别的日志
(当然还要满足root中定义的最低级别)
-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>debug</level>
</filter>
<encoder>
<!-- 日志格式(引用变量) -->
<Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
<!-- 设置字符集 -->
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- 输出到磁盘的日志文件中 -->
<appender name="file" class="ch.qos.logback.core.FileAppender">
<file>${log.path}/logback1.log</file>
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- 滚动追加到文件中 -->
<appender name="file2" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 正在记录的日志文件的路径及文件名 -->
<file>${log.path}/logback2.log</file>
<!--日志文件输出格式-->
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>UTF-8</charset> <!-- 设置字符集 -->
</encoder>
<!-- 日志记录器的滚动策略,按日期,按大小记录
文件超过最大尺寸后,会新建文件,然后新的日志文件中继续写入
如果日期变更,也会新建文件,然后在新的日志文件中写入当天日志
-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 新建文件后,原日志改名为如下 %i=文件序号,从0开始 -->
<fileNamePattern>${log.path}/logback-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<!-- 每个日志文件的最大体量 -->
<timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>5KB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
<append>true</append>
<!-- 日志文件保留天数,1=则只保留昨天的归档日志文件 ,不设置则保留所有日志-->
<maxHistory>2</maxHistory>
</rollingPolicy>
</appender>
<!--
level为日志输出级别:
trace - debug - info - warn - error
-->
<root level="debug">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="file2"/>
</root>
<!--输出到日志文件-->
<root level="info">
<appender-ref ref="file"/>
</root>
</configuration>
//1.创建调度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//2.设定任务规则
JobDetail jobDetail = JobBuilder.newJob(ClockInJob.class)
//指定任务的唯一标识
.withIdentity("clockIn", "clockIn").build();
//3.设定时间规则
CronTrigger trigger = TriggerBuilder.newTrigger().withSchedule(
//秒 分 时 日 月 星期数
//3 * * * * ? 每分钟的第3秒
//0/3 * * * * ? 一开始执行任务,每隔3秒再一次执行
//"3/3 * * * * ?" 3秒后每隔3秒执行一次
//"0-30 * * * * ?" 0-30秒每一秒执行一次
//0 0 20 ? * 6 每周周五晚上8点发周报
//0 0 1 1 * ? 每月第一天凌晨1点
CronScheduleBuilder.cronSchedule("3/3 * * * * ?"))
.build();
//4.通过调度器绑定任务和时间
scheduler.scheduleJob(jobDetail,trigger);
//5.开启调度器
scheduler.start();
Thread.sleep(10000);
//删除定时任务
scheduler.deleteJob(new JobKey("clockIn", "clockIn"));
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.qf.ran"/>
<!--
1.定义任务的 bean ,指定任务规则
-->
<bean name="job1" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!-- 指定 job 的名称-->
<property name="name" value="clockIn"/>
<!-- 指定 job 的组织 -->
<property name="group" value="clockIn"/>
<!--指定具体的 job 类-->
<property name="jobClass" value="com.qf.ran.job.ClockInJob"/>
</bean>
<!--
2.定义触发器的bean,制定时间规则
-->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="name" value="trigger1"/>
<property name="group" value="trigger1"/>
<!-- 绑定调度任务 -->
<property name="jobDetail" ref="job1"/>
<!--指定时间规则,每隔3秒执行一次-->
<property name="cronExpression" value="*/3 * * * * ?"/>
</bean>
<!--
3.创建调度器,将触发器注册到调度器里
-->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!--触发器栈-->
<property name="triggers">
<list>
<ref bean="cronTrigger"/>
</list>
</property>
<!-- 添加 quartz 配置,如下两种方式均可 -->
<!--<property name="configLocation" value="classpath:quartz.properties"></property>-->
<property name="quartzProperties">
<value>
# 指定调度器名称,实际类型为:QuartzScheduler
org.quartz.scheduler.instanceName = MyScheduler
# 指定连接池
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
# 连接池线程数量
org.quartz.threadPool.threadCount = 11
# 优先级
org.quartz.threadPool.threadPriority = 5
# 不持久化job
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
</value>
</property>
</bean>
</beans>
//集成 swagger2 需要添加注解
@WebAppConfiguration
2、swafa找不到属性,属性显示不全
参考
3、jQuery on()方法绑定动态元素
要有一个父类
1. Spring Boot
2. Shiro
3. 运维篇(了解) Linux Docker
## 微服务
#### 微服务组件
Spring Cloud
Spring Cloud Alibaba
Spring Cloud Netflix
#### 第三方常用框架
1. 分布式事务
2. 分布式锁
3. ES
4. Sharding-JDBC
5. Redis
6. 消息中间件
7. Spring Security(选学)
8. Vue(前端)
## Spring Boot笔记
### 基础
1. yml
### 数据层
1. Mybatis
2. Mybatis Plus ORM 框架的能力
3. JPA (Hibernate)
4. Redis(操作map)
### web
1. Restful
2. 参数校验
3. 全局异常处理
4. 文件上传
## 为什么要学习Spirng Boot
1. 导包
2. 内置web容器(tomcat)
3. 整合配置文件
4. 内置监控
## 什么是Spring Boot
> spring boot 简化了 spring 的开发难度,配置信息,提供了各种启动器(starter),是新一代的web开发标准, 并且spring cloud的基础
## 创建Spring Boot项目
### 概要
1. Spring Boot 初始化器
2. 手动创建(重点掌握)
### Maven多继承与多模块
如果想pom.xml文件被继承(父pom文件)
继承
1. `<packaging>pom</packaging>`
```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.10</version>
<relativePath/>
</parent>
<packaging>pom</packaging>
<groupId>com.smart</groupId>
<artifactId>spring-boot-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-example</name>
</project>
子pom文件
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<parent>
<groupId>com.smartgroupId>
<artifactId>spring-boot-exampleartifactId>
<version>0.0.1-SNAPSHOTversion>
指向pom包,一定要改过来,不然影响后续的打包
<relativePath>../pom.xmlrelativePath>
parent>
project>
补充知识点
常见的继承标签(可以继承的都可以删除)
groupId
version
properties(包括子标签)
依赖继承
build标签是不能够被继承的
spring-boot-project 项目说明标签,可要可不要
多模块
在父pom文件中
<project>
<modules>
<module>spring-boot-basemodule>
modules>
project>
备注:
@Data
public class User {
@Value("${user.username}")
private String username;
@Value("${user.password}")
private String password;
}
user:
username: admin
password: password
@Configuration
public class UserConfig {
@Bean
public User user() {
User user = new User();
return user;
}
}
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
User user;
@GetMapping("/test")
public String test() {
return user.getUsername();
}
}
@ConfigurationProperties(prefix = "" ,value="")
属性 | 说明 | |
---|---|---|
prefix等价于value | 配置文件属性前缀 | |
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-configuration-processorartifactId>
<optional>trueoptional>
dependency>
@Data
@Component
@ConfigurationProperties(prefix = "user.properties")
public class UserProperties {
private String username;
private String password;
}
user:
properties:
username: admin
password: password
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
UserProperties userProperties;
@GetMapping("/test2")
public String test2() {
return userProperties.getUsername();
}
}
说明 | 批量读取 @ConfigurationProperties | 单值读取 @Value |
---|---|---|
松散语法 | 在yml格式的配置文件中能使用 properties不支持 | 不支持 |
JSR303数据校验 | 支持 | 不支持 |
复杂数据类型 | 支持 | 不支持 |
SpEL | 不支持 | 支持 |
file > classpath config > classpath
yml或者yaml优先加载 如果出现相同的属性则会被Properties中的配置所覆盖
spring boot 支持两种配置文件格式
- properties
- yml 或者 yaml
约定优于配置
配置文件的名称必须是application开头
如果各种环境配置信息没有区别的,配置在主配置文件中
application.yml
server:
# 修改应用程序端口
port: 8888
servlet:
# 修改应用程序的前缀
context-path: "/api/v1"
# 引入多环境配置文件
spring:
profiles:
active: "dev,db"
application-dev.yml
server:
port: 8881
logging:
level: debug
application-db.yml
通过外面命令指定(了解)
java -jar app.jar --spring.profiles.active=dev
外部执行jar工程包
java -jar app.jar
<dependency>
<groupId>com.aliyun.ossgroupId>
<artifactId>aliyun-sdk-ossartifactId>
<version>3.10.2version>
dependency>
aliyun:
oss:
endpoint: " https://oss-cn-guangzhou.aliyuncs.com"
access-key-id: "LTAI5tLzBaVSAe65vuho4o3n"
access-key-secret: "K4jFCGp8evfF7gJb3gkjkUhNrScNHc"
bucket-name: "smart-2109"
@ConfigurationProperties("aliyun.oss")
@Component
public class OSSConfigProperties {
// https://oss-cn-guangzhou.aliyuncs.com
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
// smart-2109
private String bucketName;
}
配置类
@Configuration
public class AliyunOSSConfig {
@Resource
private OSSConfigProperties properties;
/**
* OSS对象注入到容器
*
* @return
*/
@Bean
public OSS oss() {
return new OSSClientBuilder()
.build(properties.getEndpoint(), properties.getAccessKeyId(), properties.getAccessKeySecret());
}
}
MultipartFile
文件的后缀名
上传文件的流
oss.putObject方法
获取图片的显示路径
@Resource
OSS oss;
@Resource
OSSConfigProperties properties;
// 图片的重名前缀
public static final String IMG_PREFIX_FILE = "IMG_";
// 云服务器存储的图片的根目录
public static final String BUCKET_NAME_IMAGE = "images";
@Override
public String uploadImage(MultipartFile multipartFile) {
/**
* 2 images/21111/xxx.png
* 获取文件的原始名称
*/
String originalFilename = multipartFile.getOriginalFilename();
// 对图片进行重命名
String newFileName = getNewFileName(originalFilename);
//
String key = BUCKET_NAME_IMAGE + File.separator + DateUtil.format(new Date(), "yyyy-MM-dd") + File.separator + newFileName;
try {
// 1 上传到阿里云OSS服务器
PutObjectResult putObjectResult = oss.putObject(properties.getBucketName(), key, multipartFile.getInputStream());
} catch (IOException e) {
throw new ServiceException(ResultCode.FILE_UPLOAD_ERROR);
}
return null;
}
/**
* 对图片进行重命名
*
* @param originalFilename
* @return
*/
private static String getNewFileName(String originalFilename) {
/**
* 自定义命名规则 + 文件的后缀名
* IMG_2022031415331234.png
* xxxx.png
*/
// 获取文件的后缀名
String suffixName = originalFilename.substring(originalFilename.lastIndexOf("."));
return String.format("%s%s%s%s", IMG_PREFIX_FILE, DateUtil.format(new DateTime(), DATE_FORMAT), RandomUtil.randomNumbers(4), suffixName);
}
获取图片的访问地址
private String getUrl(String bucketName, String key) {
Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 10);
String url = oss.generatePresignedUrl(bucketName, key, expiration).toString();
return url;
}
完整代码
@Service
public class UploadServiceImpl implements UploadService {
public static final String IMG_PREFIX_FILE = "IMG_";
public static final String DATE_FORMAT = "yyyyMMddHHmmss";
public static final String BUCKET_NAME_IMAGE = "images";
@Resource
private OSS oss;
@Resource
private OSSConfigProperties properties;
/**
* 图片覆盖
* /1/20210314/xxx.png
* 36655/按着日期对文件归类 // 可以防止图片覆盖
* // 对图片重命名
*
* @return
*/
@Override
public String uploadImage(MultipartFile multipartFile) {
/**
* 获取文件的原始名称
*/
// 判断文件的格式
String originalFilename = multipartFile.getOriginalFilename();
// 判断文件是否是上传格式
String newFileName = getNewFileName(originalFilename);
String key = BUCKET_NAME_IMAGE + File.separator + DateUtil.format(new Date(), "yyyy-MM-dd") + File.separator + newFileName;
try {
PutObjectResult putObjectResult = oss.putObject(properties.getBucketName(), key, multipartFile.getInputStream());
if (!ObjectUtil.isEmpty(putObjectResult.getETag())) {
// 表示上传成功
return getUrl(properties.getBucketName(), key);
} else {
throw new ServiceException(ResultCode.FILE_UPLOAD_ERROR);
}
} catch (IOException e) {
throw new ServiceException(ResultCode.FILE_UPLOAD_ERROR);
}
}
/**
* 对图片进行重命名
*
* @param originalFilename
* @return
*/
private static String getNewFileName(String originalFilename) {
/**
* 自定义命名规则 + 文件的后缀名
* IMG_2022031415331234.png
* xxxx.png
*/
// 获取文件的后缀名
String suffixName = originalFilename.substring(originalFilename.lastIndexOf("."));
return String.format("%s%s%s%s", IMG_PREFIX_FILE, DateUtil.format(new DateTime(), DATE_FORMAT), RandomUtil.randomNumbers(4), suffixName);
}
private String getUrl(String bucketName, String key) {
Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 10);
String url = oss.generatePresignedUrl(bucketName, key, expiration).toString();
return url;
}
}
spring:
servlet:
multipart:
enabled: true
# location: "upload/static/image"
# 单个上传的文件最大值
max-file-size: 10MB
# 一起请求上传文件的最大值
max-request-size: 100MB
/**
* 文件上传
* 1. 上传的本地的服务器
* 2. 上传到云对象存储 OSS
* 3 FastDFS (技术要求高)
* @return
*/
@PostMapping("/upload/img")
public ResponseResult<String> uploadImage(@RequestBody MultipartFile multipartFile) {
String url = uploadService.uploadImage(multipartFile);
return ResponseResult.success(url);
}
课外延展:
@Configuration注解的更具体用法
@Configuration
CREATE TABLE banner
(
banner_id int AUTO_INCREMENT COMMENT '主键' PRIMARY KEY,
name varchar(10) NOT NULL COMMENT '名称',
description varchar(64) DEFAULT '' NOT NULL COMMENT '描述',
img varchar(255) NOT NULL COMMENT '轮播图的路径',
link_status int DEFAULT 1 NOT NULL COMMENT '1 表示启用 0 表示禁用',
link int DEFAULT 1 NOT NULL COMMENT '1 表示全部店铺, 2 表示指定店铺',
link_jump int DEFAULT 0 NOT NULL COMMENT '0 表示不跳转商品信息 1 表示跳转商品链接',
product_id bigint DEFAULT -1 NOT NULL COMMENT '跳转的商品ID',
type int NULL COMMENT '1 表示pc端 2 表示 移动端',
create_date datetime DEFAULT CURRENT_TIMESTAMP NULL COMMENT '表示创建时间',
is_del int DEFAULT 0 NOT NULL COMMENT '0 不删除 1 表示删除',
CONSTRAINT name UNIQUE (name)
);
@PostMapping("/add")
public ResponseResult<Integer> add(@Validated(BannerRequestParams.Add.class) @RequestBody BannerRequestParams banner) {
int count = bannerService.add(banner);
return ResponseResult.success(count);
}
/**
* @author zhangwei
*/
@Data
@Validated
public class BannerRequestParams {
public interface Add {
}
public interface Update {
}
/**
* 主键
*/
@NotNull(groups = Update.class)
private Integer bannerId;
/**
* 名称
*/
@Length(min = 1, max = 10, message = "最多10个字")
private String name;
/**
* 描述
*/
private String description;
/**
* 轮播图的路径
*/
@NotNull
private String img;
/**
* 1 表示启用 0 表示禁用
*/
private Integer linkStatus;
/**
* 1 表示全部店铺, 2 表示指定店铺
*/
private Integer link;
/**
* 0 表示不跳转商品信息 1 表示跳转商品链接
*/
private Integer linkJump;
/**
* 跳转的商品ID
*/
private Long productId;
/**
* 1 表示pc端 2 表示 移动端
*/
private Integer type;
//上传时使用
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createDate;
}
/**
* @author zhangwei
*/
@Service
public class BannerServiceImpl implements BannerService {
@Resource
private BannerMapper bannerMapper;
@Override
public int add(BannerRequestParams banner) {
Banner bannerEntity = new Banner();
/**
* 第一个参数有值 第二个没值
*/
BeanUtils.copyProperties(banner, bannerEntity);
int count = bannerMapper.insert(bannerEntity);
if (count > 0) {
return count;
} else {
throw new ServiceException(ResultCode.ERROR);
}
}
}
public interface BannerMapper extends BaseMapper {
}
@Data
@TableName(value = "banner")
public class Banner {
/**
* 主键
*/
@TableId(value = "banner_id", type = IdType.INPUT)
private Integer bannerId;
/**
* 名称
*/
@TableField(value = "`name`")
private String name;
/**
* 描述
*/
@TableField(value = "description")
private String description;
/**
* 轮播图的路径
*/
@TableField(value = "img")
private String img;
/**
* 1 表示启用 0 表示禁用
*/
@TableField(value = "link_status")
private Integer linkStatus;
/**
* 1 表示全部店铺, 2 表示指定店铺
*/
@TableField(value = "link")
private Integer link;
/**
* 0 表示不跳转商品信息 1 表示跳转商品链接
*/
@TableField(value = "link_jump")
private Integer linkJump;
/**
* 跳转的商品ID
*/
@TableField(value = "product_id")
private Long productId;
/**
* 1 表示pc端 2 表示 移动端
*/
@TableField(value = "`type`")
private Integer type;
/**
* 表示创建时间
*/
@TableField(value = "create_date")
private Date createDate;
/**
* 0 不删除 1 表示删除
*/
@TableField(value = "is_del")
private Integer isDel;
public static final String COL_BANNER_ID = "banner_id";
public static final String COL_NAME = "name";
public static final String COL_DESCRIPTION = "description";
public static final String COL_IMG = "img";
public static final String COL_LINK_STATUS = "link_status";
public static final String COL_LINK = "link";
public static final String COL_LINK_JUMP = "link_jump";
public static final String COL_PRODUCT_ID = "product_id";
public static final String COL_TYPE = "type";
public static final String COL_CREATE_DATE = "create_date";
public static final String COL_IS_DEL = "is_del";
}
@Data
public class BannerVo {
/**
* 主键
*/
private Integer bannerId;
/**
* 名称
*/
private String name;
/**
* 描述
*/
private String description;
/**
* 轮播图的路径
*/
private String img;
/**
* 1 表示启用 0 表示禁用
*/
private Integer linkStatus;
/**
* 1 表示全部店铺, 2 表示指定店铺
*/
private Integer link;
/**
* 0 表示不跳转商品信息 1 表示跳转商品链接
*/
private Integer linkJump;
/**
* 跳转的商品ID
*/
private Long productId;
/**
* 1 表示pc端 2 表示 移动端
*/
private Integer type;
//json数据序列化指定日期格式
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createDate;
}
spring:
# 配置json数据统一的日志解析格式
jackson:
date-format: "yyyy-MM-dd HH:mm:ss"