Spring5常用注解
@Autowired 自动装配 通过类型 ByType
若Autowired不能唯一自动装配上属性,则需要通过@Qualifier(Value=“XXX”)
@Resource 自动装配 通过名字、类型 ByName ByType
@Nullable 字段标记了该注解,说明这个字段可以为null
@Component 组件,放在类上,说明这个类被spring管理了(就是bean)
@Repository 用在dao层(或Mapper层),作用:被spring管理
@Service 用在service层,作用:被spring管理
@controller 或 @RestController用在controller层,作用:被spring管理
@RestController
Spring4之后新加入的注解,原来返回json需要@ResponseBody和@Controller配合。
即@RestController是@ResponseBody和@Controller的组合注解。
@ConfigurationProperties 用在实体类上,结合springboot的yaml配置中使用
@Mapper //注解表示这是一个mybatis的mapper类
@Mapper //注解表示这是一个mybatis的mapper类
public class UserMapper {
}
@MapperScan(“com.example.demo.mapper”)效果与@Mapper一样
@SpringBootApplication
@MapperScan("com.example.demo.mapper")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Springboot笔记
关于springboot+vue前后端分离的跨域问题
//跨域
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("*")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
}
松散笔记
根据源码显示静态资源目录可以添加resources、public,且首页index.html页面在public、resources、static中可以直接显示,但在templates中需要添加模板引擎thymeleaf
thymeleaf引入xmlns:th=“http://www.thymeleaf.org”
在springboot中扩展springmvc,添加@Configuration 实现WebMvcConfigurer接口
springboot使用thymeleaf补充
1.在pom.xml导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2.在templates下创建index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>首页</h1>
<p th:text="${msg}"></p>
</body>
</html>
3.在contorller跳转至index.html,通过Model传入数据,注意不能使用@RestController
@Controller
public class MyController {
@RequestMapping({"/","/index"})
public String toIndex(Model model){
model.addAttribute("msg","hello,shiro");
return "index";
}
}
在springboot的配置文件中
thymeleaf的国际化
注:mysql的jdbc配置,mysql8.0+需要写上时区,serverTimezone=GMT
jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT
springboot整合Druid
#SpringBoot默认是不注入这些的,需要自己绑定
#druid数据源专有配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
#配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
#如果允许报错,java.lang.ClassNotFoundException: org.apache.Log4j.Properity
#则导入log4j 依赖就行
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionoProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
在.yaml文件中通过type修改为Druid
引入pom.xml
在DruidConfig中绑定yaml中的配置
druid后台监控功能
通过/druid进入
springboot整合mybatis
官网:https://mybatis.org/mybatis-3/zh/getting-started.html
1.pom.xml导入mybatis
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
2.在resources下创建mapper.xml文件
<?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.example.demo.mapper.UserMapper">
<select id="queryUserList" resultType="User">
select * from User
</select>
<select id="queryUserById" resultType="User">
select * from User where id= #{id}
</select>
</mapper>
3.在application.properties配置文件
spring.datasource.username=root
spring.datasource.password=zzp
spring.datasource.url=jdbc:mysql://localhost:3306/login?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#整合mybatis
mybatis.type-aliases-package=com.example.demo.pojo
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml;
4.mapper层的mapper接口文件添加@Mapper注解或者在启动类添加@MapperScan(“com.example.demo.mapper”)扫描
@Mapper //表示该类是一个mybatis的mapper类
@Repository
public interface UserMapper {
List<User> queryUserList();
User queryUserById(int id);
int addUser(User user);
int updateUser(User user);
int deleteUser(int id);
}
@SpringBootApplication
//@MapperScan("com.example.demo.mapper")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
springboot中SpringSecurity环境搭建
(需注意springboot版本问题)
1.在pom.xml中引入依赖
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-security -->
<!-- security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
2.创建SecurityConfig
//AOP拦截器
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//授权
@Override
protected void configure(HttpSecurity http) throws Exception {
//链式编程
//首页所有人可以访问,功能页只有对应有权限的人才能访问
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/levle1").hasRole("vip");
//无权限默认会到登录页面,需要开启登录页面
http.formLogin();
//注销,开启功能
http.logout().logoutSuccessUrl("/");//登出并跳转
//开启记住我功能
http.rememberMe();
}
//认证
//认证,springboot2.1.x 可以直接使用
//需要密码加密:PasswordEncoder
//在Spring Security 5.0+新增了很多的加密方法
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("456").password(new BCryptPasswordEncoder().encode("456")).roles("vip")
.and()//通过and()拼接下一个用户
.withUser("root").password(new BCryptPasswordEncoder().encode("admin")).roles("vip");
}
}
Springboot+vue中EasyExcel(占用内存小)的使用
springboot+vue结合easyexcel的导出
1.在springboot项目pom.xml中导入easyexcel的依赖
<!--EasyExcel-->
<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.6</version>
</dependency>
2.创建ExcelUtil.java的工具类
/**
* 导出excel工具类
* response 返回对象
* list excel表中记录
*
*/
public class ExcelUtil {
public static void writeExcel(HttpServletResponse response, List<PingpangIntegral> list) throws IOException {
ExcelWriter excelWriter= EasyExcel.write(response.getOutputStream()).build();
//定义工作表对象
WriteSheet sheet=EasyExcel.writerSheet(0,"Sheet").head(PingpangIntegral.class).build();
//往excel文件中写入数据
excelWriter.write(list,sheet);
//关闭输出流
excelWriter.finish();;
}
}
3.在实体类上添加@ExcelProperty(“列名”)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PingpangIntegral implements Serializable {
@ExcelProperty("id")
private Integer id;
/**
* 积分差区间下限
*/
@ExcelProperty("pingpangLow")
private Integer pingpangLow;
4.在controller层调用
@RequestMapping(value = "/export",method = RequestMethod.POST)
public void export(HttpServletResponse response,@RequestBody PingpangIntegral pingpangIntegral) throws IOException {
int kinds=pingpangIntegral.getPingpangKinds();
List list= pingpangService.query(kinds);
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition","attachment;filename="+"_.xlsx");
ExcelUtil.writeExcel(response,list);
}
@RequestMapping(value = "/exportAll",method = RequestMethod.GET)
public void exportAll(HttpServletResponse response) throws IOException {
List list= pingpangService.selectAll();
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition","attachment;filename="+"_.xlsx");
ExcelUtil.writeExcel(response,list);
}
5.在前端vue获取
methods: {
handleExportXls() {
if(this.value==null){
axios.get('http://localhost:8081/exportAll',{
responseType: 'blob'
}).then((res)=>{
this.downloadFile(res.data);
}).catch(function (error) {
})
}
else {
axios.post('http://localhost:8081/export',{
pingpangKinds:this.value,
},{
responseType: 'blob'
}).then((res)=>{
this.downloadFile(res.data);
}).catch(function (error) {
})
}
},
downloadFile(data) {
if (!data) {
return
}
const link = document.createElement('a');
let blob = new Blob([data], {type: 'application/vnd.ms-excel'});
link.style.display = 'none';
link.href = URL.createObjectURL(blob);
link.setAttribute('download', '记录信息' + '.xlsx');
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
},
}
注意需要在axios的config中配置 responseType: ‘blob’
springboot+vue结合easyexcel的导入
点击进入:easyexcel官网
1.导入easyexcel的依赖
<!--EasyExcel-->
<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.6</version>
</dependency>
2.实体类上有@ExcelProperty
@ExcelProperty("id")
private Integer id;
@ExcelProperty("pingpangLow")
private Integer pingpangLow;
3.DAO
@Mapper
public interface PingpangIntegralDao {
void save(List<PingpangIntegral> list);
}
注意导入需要插入数据库操作时,若用的时mybatis可以编写模块插入的sql语句
<insert id="save" parameterType="List" >
insert into pingpang_integral (id,pingpangLow, pingpangUp, pingpangHeight,
pingpangLower, pingpangLoserUp, pingpangLoserLower,
pingpangKinds)
VALUES
<foreach collection="list" index="index" item="item" separator=",">
(#{item.id},#{item.pingpangLow},#{item.pingpangUp},#{item.pingpangHeight},#{item.pingpangLower},#{item.pingpangLoserUp},#{item.pingpangLoserLower},#{item.pingpangKinds})
</foreach>
</insert>
4.监听器配置
package demo.util;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import demo.dao.PingpangIntegralDao;
import demo.pojo.PingpangIntegral;
import org.mybatis.logging.Logger;
import org.mybatis.logging.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
public class DemoDataListener extends AnalysisEventListener<PingpangIntegral> {
private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class);
/**
* 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 5;
List<PingpangIntegral> list = new ArrayList<PingpangIntegral>();
/**
* 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
*/
private PingpangIntegralDao pingpangIntegralDao;
public DemoDataListener() {
// 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
}
/**
* 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
*
* @param
*/
public DemoDataListener(PingpangIntegralDao pingpangIntegralDao) {
this.pingpangIntegralDao = pingpangIntegralDao;
}
/**
* 这个每一条数据解析都会来调用
*
* @param data
* one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
@Override
public void invoke(PingpangIntegral data, AnalysisContext context) {
System.out.println(JSON.toJSONString(data));
list.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (list.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
list.clear();
}
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
System.out.println("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() {
System.out.println(list.size()+"条数据,开始存储数据库!");
pingpangIntegralDao.save(list);
System.out.println("存储数据库成功!");
}
}
5.controller层
@RequestMapping(value = "/input",method = RequestMethod.POST)
public String upload(@RequestBody MultipartFile file) throws IOException {
System.out.println(file);
EasyExcel.read(file.getInputStream(), PingpangIntegral.class, new DemoDataListener( pingpangIntegralDao)).sheet().doRead();
return "success";
// String PATH="C:\\Users\\指尖王者\\Desktop\\";
// String fileName = PATH + "记录信息.xlsx";
// // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
// EasyExcel.read(fileName, PingpangIntegral.class, new DemoDataListener(pingpangIntegralDao)).sheet().doRead();
// return "success";
}
6.vue端传入file
1.使用el-upload上传文件
<el-upload
class="upload-demo inline-block"
action="uploadExcel"
:http-request="httpRequest"
:before-upload="beforAvatarUpload"
:show-file-list="false">
<el-button type="primary" icon="el-icon-download" size="small" >导入</el-button>
</el-upload>
<!--inline-block使el-upload与普通按钮在同一行-->
.inline-block {
display: inline-block;
}
2.导入前判断文件格式
//判断文件类型是否正确
beforAvatarUpload(file){
const isxls=file.type==="application/vnd.ms-excel"?true:file.type==="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"?true:false;
if(!isxls){
this.$message.error("只能上传.xls或.xlsx格式文件")
}
return isxls
},
3.导入excel
//导入excel
httpRequest(params){
let formdata=new FormData();
formdata.append("file",params.file);
let config = {
// 一定要定义头
headers: {
'Content-Type': 'multipart/form-data'
}
}
axios.post('http://localhost:8081/input',formdata,config).then((res)=>{
console.log(res.status)
if(res.status==200){
this.$message({
message: '导入成功',
type: 'success'
});
}
}).catch(res=> {
if(res.status!=200){
this.$message.error('导入失败(注:不能导入已有数据)')
}
})
需注意formdata与config定义头
let formdata=new FormData();
formdata.append("file",params.file);
let config = {
// 一定要定义头
headers: {
'Content-Type': 'multipart/form-data'
}
}
axios.post('http://localhost:8081/input',formdata,config).then((res)=>{}
Apache POI(占用内存较大)
springboot整合shiro
1.在pom.xml中导入依赖
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
2.自定义一个realm
UserRealm
//自定义的realm
public class UserRealm extends AuthorizingRealm {
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行了授权");
return null;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了认证");
return null;
}
}
3.创建ShiroConfig
@Configuration
public class shiroConfig {
//ShiroFileterFactoryBean(第三步)
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
return shiroFilterFactoryBean;
}
//DefaultWebSecurityManager(第二步)
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联UserRealm
securityManager.setRealm(userRealm);
return securityManager;
}
//创建realm对象,需要自定义(第一步)
@Bean(name = "userRealm")//name属性可省略
public UserRealm userRealm(){
return new UserRealm();
}
shiro实现拦截登录
1.在shiroConfig中配置
//ShiroFileterFactoryBean(第三步)
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean sfb = new ShiroFilterFactoryBean();
//设置安全管理器
sfb.setSecurityManager(defaultWebSecurityManager);
//添加shiro的内置过滤器
/*
* anon:无需认证就可以访问
* authc:必须认证才能访问
* user:必须拥有 “记住我” 功能才能访问
*perms:拥有对某个资源的权限才能访问
*role:拥有某个角色权限才能访问
* */
Map<String, String> filterMap=new LinkedHashMap<>();
filterMap.put("/user/add","anon");
filterMap.put("/user/update","authc");
sfb.setFilterChainDefinitionMap(filterMap);
//设置登录的请求
sfb.setLoginUrl("/toLogin");
return sfb;
}
shiro实现用户认证
1.controller层
@RequestMapping("/login")
public String login(String username, String password, Model model) {
//获取当前的用户
Subject subject = SecurityUtils.getSubject();
//封装用户的登录数据
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
subject.login(token);//执行登录方法,如果没有异常就说明ok
return "index";
} catch (UnknownAccountException e) {//用户名不存在
model.addAttribute("msg", "用户名错误");
return "user/login";
} catch (IncorrectCredentialsException e) {//密码不存在
model.addAttribute("msg", "密码错误");
return "user/login";
}
}
2.UserRealm
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了认证");
//用户名 密码 一般从数据库中获取 用于校验
String name="root";
String password="123";
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
if (!userToken.getUsername().equals(name)) {
return null;//抛出异常 UnknownAccountException
}
//密码认证 shiro自行完成 防止接触密码泄露
return new SimpleAuthenticationInfo("",password,"");
}
shiro整合mybatis(Druid数据源)
1.在pom.xml导入依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
2.配置application.yaml
#SpringBoot默认是不注入这些的,需要自己绑定
#druid数据源专有配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
#配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
#如果允许报错,java.lang.ClassNotFoundException: org.apache.Log4j.Properity
#则导入log4j 依赖就行
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionoProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
3.在applica.properties配置mybatis
# thymeleaf
spring.thymeleaf.cache=false
#配置mybatis
mybatis.type-aliases-package=com.example.pojo
mybatis.mapper-locations=classpath:mapper/*.xml
4.修改UserRealm中的用户名和密码为数据库的信息即可
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了认证");
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
//用户名 密码 一般从数据库中获取 用于校验
User user=userService.selectname(userToken.getUsername());
if (user==null) {
return null;//抛出异常 UnknownAccountException
}
//密码认证 shiro自行完成 防止接触密码泄露
return new SimpleAuthenticationInfo("",user.getPassword(),"");
}
shiro请求授权实现
1.在shiroConfig第三步中设置权限拦截
//ShiroFileterFactoryBean(第三步)
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
ShiroFilterFactoryBean sfb = new ShiroFilterFactoryBean();
//设置安全管理器
sfb.setSecurityManager(defaultWebSecurityManager);
//添加shiro的内置过滤器
/*
* anon:无需认证就可以访问
* authc:必须认证才能访问
* user:必须拥有 “记住我” 功能才能访问
*perms:拥有对某个资源的权限才能访问
*role:拥有某个角色权限才能访问
* */
//拦截
Map<String, String> filterMap=new LinkedHashMap<>();
//用户拥有“user:add”权限时 客访问
filterMap.put("/user/add","perms[user:add]");
//用户通过auchc认证后可访问
filterMap.put("/user/update","perms[user:update]");
sfb.setFilterChainDefinitionMap(filterMap);
//设置登录的请求, 未登录则跳转至该页面
sfb.setLoginUrl("/toLogin");
//未授权则跳转至该页面
sfb.setUnauthorizedUrl("/unauthorized");
return sfb;
}
2.在UserRealm中授予权限,通过获取用户表中的权限列,授予相应权限
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("执行了授权");
//SimpleAuthorizationInfo执行授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//该位置将会给每个用户授于“user:add”权限
// info.addStringPermission("user:add");
//拿到当前登录的这个对象
Subject subject = SecurityUtils.getSubject();
User currentUser = (User) subject.getPrincipal();//可以拿到SimpleAuthenticationInfo(user,user.getPassword(),"")中的user
//设置当前用户的权限
System.out.println(currentUser);
System.out.println(currentUser.getPerms());
info.addStringPermission(currentUser.getPerms());
if(currentUser.getPerms()!=null){
return info;
}
else {
return null;
}
}
shiro整合Thymeleaf
1.导入依赖
<!--shiro整合thymeleaf-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
2.在UserRealm的认证登录成功时获取session
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("执行了认证");
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
//用户名 密码 一般从数据库中获取 用于校验
User user=userService.selectname(userToken.getUsername());
if (user==null) {
return null;//抛出异常 UnknownAccountException
}
//登时成功时,获取session
Subject currentsubject = SecurityUtils.getSubject();
Session session = currentsubject.getSession();
session.setAttribute("loginUser",user);
//密码认证 shiro自行完成 防止接触密码泄露
return new SimpleAuthenticationInfo(user,user.getPassword(),"");
}
3.首页index.html页面
通过该xmlns整合shiro与thymeleaf
xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>首页</h1>
<p th:text="${msg}"></p>
<div th:if="${session.loginUser==null}">
<a th:href="@{/toLogin}">登录</a>
</div>
<hr>
<div shiro:hasPermission="user:add">
<a th:href="@{/user/add}">add</a>
</div>
<div shiro:hasPermission="user:update">
<a th:href="@{/user/update}">update</a>
</div>
</body>
</html>
AutoPOI(Excel工具)的使用方法
/**
* 导出excel
*
* @param request
*/
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(SysAnnouncement sysAnnouncement,HttpServletRequest request) {
// Step.1 组装查询条件
QueryWrapper<SysAnnouncement> queryWrapper = QueryGenerator.initQueryWrapper(sysAnnouncement, request.getParameterMap());
//Step.2 AutoPoi 导出Excel
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
List<SysAnnouncement> pageList = sysAnnouncementService.list(queryWrapper);
//导出文件名称
mv.addObject(NormalExcelConstants.FILE_NAME, "系统通告列表");
mv.addObject(NormalExcelConstants.CLASS, SysAnnouncement.class);
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("系统通告列表数据", "导出人:"+user.getRealname(), "导出信息"));
mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
return mv;
}
/**
* 通过excel导入数据
*
* @param request
* @param response
* @return
*/
@RequestMapping(value = "/importExcel", method = RequestMethod.POST)
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
MultipartFile file = entity.getValue();// 获取上传文件对象
ImportParams params = new ImportParams();
params.setTitleRows(2);
params.setHeadRows(1);
params.setNeedSave(true);
try {
List<SysAnnouncement> listSysAnnouncements = ExcelImportUtil.importExcel(file.getInputStream(), SysAnnouncement.class, params);
for (SysAnnouncement sysAnnouncementExcel : listSysAnnouncements) {
if(sysAnnouncementExcel.getDelFlag()==null){
sysAnnouncementExcel.setDelFlag(CommonConstant.DEL_FLAG_0.toString());
}
sysAnnouncementService.save(sysAnnouncementExcel);
}
return Result.ok("文件导入成功!数据行数:" + listSysAnnouncements.size());
} catch (Exception e) {
log.error(e.getMessage(),e);
return Result.error("文件导入失败!");
} finally {
try {
file.getInputStream().close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return Result.error("文件导入失败!");
}
springboot结合PageHelper的分页查询
1.导入pagehelper依赖
<!--pagehelper-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
2.配置PageHelperConfig文件
import com.github.pagehelper.PageHelper;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
@Configuration
public class PageHelperConfig {
public PageHelper getPageHelper() {
PageHelper pageHelper = new PageHelper();
Properties properties = new Properties();
properties.setProperty("offsetAsPageNum","true");
properties.setProperty("rowBoundsWithCount","true");
properties.setProperty("reasonable","true");
//配置数据库方言
properties.setProperty("dialect","mysql");
pageHelper.setProperties(properties);
return pageHelper;
}
}
3.service以及serviceImpl
Service
import com.github.pagehelper.PageInfo;
import demo.pojo.PingpangIntegral;
public interface PageService {
PageInfo<PingpangIntegral> findByPage(int pageNum, int pageSize);
}
ServiceImpl
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import demo.dao.PingpangIntegralDao;
import demo.pojo.PingpangIntegral;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class PageServiceImpl implements PageService {
@Resource
private PingpangIntegralDao pingpangIntegralDao;
@Override
public PageInfo<PingpangIntegral> findByPage(int pageNum, int pageSize) {
//分页查询,会对紧跟着的第一个select方法进行分页查询,后面除非再次调用否则不会进行分页
PageHelper.startPage(pageNum, pageSize);
List<PingpangIntegral> articleList = pingpangIntegralDao.selectAll();
// int totalNum = pingpangIntegralDao.count();
PageInfo<PingpangIntegral> pageInfo = new PageInfo<>();
//设置当前页
pageInfo.setPageNum(pageNum);
//设置每页的数量
pageInfo.setPageSize(pageSize);
//设置当前页的数量
pageInfo.setSize(pageSize);
//设置结果集
pageInfo.setList(articleList);
return pageInfo;
}
}
4.application.properties(可不配置)
#分页助手pageHelper的配置 application.properties配置(可选,因为mybatis会自动配置):
#pagehelper.helper-dialect=mysql
#
#pagehelper.params=count=countSql
#
#pagehelper.reasonable=true
#
#pagehelper.support-methods-arguments=true
5.contorller层(PingpangIntegral为实体类)
@RestController
public class PageController {
@Autowired
private PageService pageService;
/**
* 分页查询
* @param pageNum //当前是第几页
* @param pageSize //每页的数量
* @return
*/
@RequestMapping("/findByPage")
@ResponseBody
public PageInfo<PingpangIntegral> findByPage(@RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "5") int pageSize) {
//分页查询
PageInfo<PingpangIntegral> pageInfo = pageService.findByPage(pageNum, pageSize);
//将数据转换为json
// String jsonString = JSON.toJSONString(pageInfo);
return pageInfo;
}
}
springboot结合swagger
1.导入springfox-swagger-ui与springfox-swagger2依赖
<!--swagger-->
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
或者导入
<!-- https://mvnrepository.com/artifact/com.spring4all/swagger-spring-boot-starter -->
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>1.9.1.RELEASE</version>
</dependency>
2.配置SwaggerConfig
@Configuration
@EnableSwagger2 //开启Swagger2
public class SwaggerConfig {
}
3.通过访问http://localhost:8080/swagger-ui.html可打开swagger页面(注:3.0.0版本无法打开swagger页面,可以降级)
4.配置Swagger
Swagger的bean实例Docket
@Configuration
@EnableSwagger2 //开启Swagger2
public class SwaggerConfig {
//配置Swagger的Docket的bean实例
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo());
}
//配置Swagger新消息 apiInfo
private ApiInfo apiInfo(){
//作者信息
Contact contact = new Contact("森", "https://www.baidu.com", "2460718527@qq.com");
return new ApiInfo("我的SwaggerApi文档",
"酷裤的森",
"1.0",
"urn:tos",
contact, //放contact,默认值为 DEFAULT_CONTACT
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList<VendorExtension>());
}
}
5.Swagger配置扫描接口
Docket.select()
//配置Swagger的Docket的bean实例
@Bean
public Docket docket(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.enable(true) //是否启动swagger,若为false,则swagger不能再浏览器中访问
.select()
//RequestHandlerSelectors 配置要扫描接口的方式
//basePackage 扫描指定包 apis(RequestHandlerSelectors.basePackage("com.example.swagger.controller"))
//any() 扫描全部
//none() 不扫描
//withClassAnnotation() 扫描类上的注解,参数为一个注解的反射对象
//withMethodAnnotation() 扫描方法上的注解,参数为一个注解的反射对象,只扫描有GetMapping的
.apis(RequestHandlerSelectors.withMethodAnnotation(GetMapping.class))
//paths() 过滤路径 只扫描有example请求的接口
.paths(PathSelectors.ant("/example/**"))
.build();
}
6.实现Swagger在开发环境中使用,在发布时不使用
(1)新建application-dev.properties(开发环境)
server.port=8081
application-pro.properties(发布环境)
server.port=8082
application.properties 选择激活某一环境
#激活dev环境
spring.profiles.active=dev
(2)配置SwaggerConfig
@Configuration
@EnableSwagger2 //开启Swagger2
public class SwaggerConfig {
//配置Swagger的Docket的bean实例
@Bean
public Docket docket(Environment environment){
//设置要显示的swagger环境
Profiles profiles=Profiles.of("dev","test");//可存在多个环境变量实例dev、test
//获取项目的环境:
environment.getActiveProfiles();
//通过environment.acceptsProfiles判断是否处在自己设定的环境中
boolean flag = environment.acceptsProfiles(profiles);
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.enable(flag) //是否启动swagger,若为false,则swagger不能再浏览器中访问
.select()
//RequestHandlerSelectors 配置要扫描接口的方式
//basePackage 扫描指定包 apis(RequestHandlerSelectors.basePackage("com.example.swagger.controller"))
//any() 扫描全部
//none() 不扫描
//withClassAnnotation() 扫描类上的注解,参数为一个注解的反射对象
//withMethodAnnotation() 扫描方法上的注解,参数为一个注解的反射对象,只扫描有GetMapping的
// .apis(RequestHandlerSelectors.withMethodAnnotation(GetMapping.class))
//paths() 过滤路径 只扫描有hello请求的接口
.paths(PathSelectors.ant("/hello/**"))
.build();
}
//配置Swagger新消息 apiInfo
private ApiInfo apiInfo(){
//作者信息
Contact contact = new Contact("森", "https://www.baidu.com", "2460718527@qq.com");
return new ApiInfo("我的SwaggerApi文档",
"酷裤的森",
"1.0",
"urn:tos",
contact, //放contact,默认值为 DEFAULT_CONTACT
"Apache 2.0",
"http://www.apache.org/licenses/LICENSE-2.0",
new ArrayList<VendorExtension>());
}
}
7.配置API文档分组
(1)配置一个组的名称
//return new Docket(DocumentationType.SWAGGER_2)
//.apiInfo(apiInfo())
.groupName("组的名称")
(2)配置多个组 (即在SwaggerConfig中创建多个Docket实例)
@Configuration
@EnableSwagger2 //开启Swagger2
public class SwaggerConfig {
//多个Docket
@Bean
public Docket docket1(){
return new Docket(DocumentationType.SWAGGER_2).groupName("A");
}
@Bean
public Docket docket2(){
return new Docket(DocumentationType.SWAGGER_2).groupName("B");
}
@Bean
public Docket docket3(){
return new Docket(DocumentationType.SWAGGER_2).groupName("C");
}
8.contorller中配置
//接口中返回值中存在实体类,就会被扫描到swagger中
@PostMapping("/user")
public User user(){
return new User();
}
9.在实体类中添加说明
@ApiModel("用户实体类") //在swagger中给实体类添加说明
public class User {
@ApiModelProperty("用户名") //在swagger中给属性添加说明
public String username;
@ApiModelProperty("用户名")
public String password;
}
10.@Api注释用法
//@ApiOperation()放在接口上
@ApiOperation("hello2接口")
@GetMapping(value = "/hello2")
public String hello2(@ApiParam("用户名") String username){
return "hello"+username;
}
jeecg-boot统一文件上传规则.
1.配置application.yaml文件
#jeecg专用配置
jeecg :
# 本地:local\Minio:minio\阿里云:alioss
uploadType: local
path :
#文件上传根目录 设置
upload: D://opt//upFiles
#webapp文件路径
webapp: D://opt//webapp
#短信秘钥
sms:
accessKeyId: ??
accessKeySecret: ??
shiro:
excludeUrls: /test/jeecgDemo/demo3,/test/jeecgDemo/redisDemo/**
#阿里云oss存储配置
oss:
endpoint: oss-cn-beijing.aliyuncs.com
accessKey: ??
secretKey: ??
bucketName: jeecgos
staticDomain: https://static.jeecg.com
# ElasticSearch 6设置
elasticsearch:
cluster-name: jeecg-ES
cluster-nodes: 127.0.0.1:9200
check-enabled: false
# 表单设计器配置
desform:
# 主题颜色(仅支持 16进制颜色代码)
theme-color: "#1890ff"
# 在线预览文件服务器地址配置
file-view-domain: http://fileview.jeecg.com
# minio文件上传
minio:
minio_url: http://minio.jeecg.com
minio_name: ??
minio_pass: ??
bucketName: otatest
2.controller层
/**
* 文件上传统一方法
* @param request
* @param response
* @return
*/
@PostMapping(value = "/upload")
public Result<?> upload(HttpServletRequest request, HttpServletResponse response) {
Result<?> result = new Result<>();
String savePath = "";
String bizPath = request.getParameter("biz");
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
MultipartFile file = multipartRequest.getFile("file");// 获取上传文件对象
if(oConvertUtils.isEmpty(bizPath)){
if(CommonConstant.UPLOAD_TYPE_OSS.equals(uploadType)){
//未指定目录,则用阿里云默认目录 upload
bizPath = "upload";
//result.setMessage("使用阿里云文件上传时,必须添加目录!");
//result.setSuccess(false);
//return result;
}else{
bizPath = "";
}
}
if(CommonConstant.UPLOAD_TYPE_LOCAL.equals(uploadType)){
//针对jeditor编辑器如何使 lcaol模式,采用 base64格式存储
String jeditor = request.getParameter("jeditor");
if(oConvertUtils.isNotEmpty(jeditor)){
result.setMessage(CommonConstant.UPLOAD_TYPE_LOCAL);
result.setSuccess(true);
return result;
}else{
savePath = this.uploadLocal(file,bizPath);
}
}else{
savePath = sysBaseAPI.upload(file,bizPath,uploadType);
}
if(oConvertUtils.isNotEmpty(savePath)){
result.setMessage(savePath);
result.setSuccess(true);
}else {
result.setMessage("上传失败!");
result.setSuccess(false);
}
return result;
}
3.vue端结合ant design vue
<template>
<div>
<a-upload
list-type="picture"
action="http://127.0.0.1:8081/jeecg-boot/upload"
:preview-file="previewFile"
>
<a-button> <a-icon type="upload" /> Upload </a-button>
</a-upload>
</div>
</template>
<script>
export default {
name: "Video",
methods: {
previewFile(file) {
console.log('Your upload file:', file);
// Your process logic. Here we just mock to the same file
return fetch('http://127.0.0.1:8081/jeecg-boot/upload', {
method: 'POST',
body: file,
})
.then(res => res.json())
.then(({ thumbnail }) => thumbnail);
},
},
};
</script>
<style scoped>
</style>
springboot结合redis
1.导入pom依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.配置连接
#配置redis
spring.redis.host=127.0.0.1
spring.redis.port=6379
3.测试类
package com.example;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;
@SpringBootTest
class SpringbootRedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
//redisTemplate 操作不同数据类型 常用的方法都可以通过redisTemplate操作
//opsForCluster() 操作字符串 类似String
//opsForList() 操作List 类似List
// 获取redis的连接对象
// RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
// connection.flushDb();
// connection.flushAll();
redisTemplate.opsForValue().set("mykey","zzp帅哥");
System.out.println(redisTemplate.opsForValue().get("mykey"));
}
}
springboot结合mybatis-plus
1.导入pom依赖
<!--引入mabatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
2.配置在application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/login?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT
spring.datasource.username=root
spring.datasource.password=zzp
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#mybatis日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
3.在UserMapper继承BaseMapper类
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
Springboot自带MD5加密
import org.springframework.util.DigestUtils;
//对密码进行 md5 加密
String md5Password = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());