system目录下是整个系统的跳转关系,有登录验证,控制菜单的跳转,和一系列的验证操作
product目录下是用户看到的页面信息,就是管理的产品数据在页面中的显示控制。
common目录是一些组件,帮助用户系统验证或者配置一些其他的配置。
教程1
教程2
//druid配置访问页面
@Configuration
public class DruidConfig {
// 真正整合的地方
@ConfigurationProperties(prefix = "spring.datasource")
@Bean(name="dataSource")
public DataSource dataSource(){
return new DruidDataSource();
}
//配置Druid监控
@Bean
public ServletRegistrationBean statViewServlet(){
//StatViewServlet是druid内置的用来展示druid统计信息的页面,注册为服务servlet后可以使用
ServletRegistrationBean bean=new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
Map<String,String> initParams=new HashMap<>();
initParams.put("allow", "127.0.0.1");// IP白名单 (没有配置或者为空,则允许所有访问)
// IP黑名单 (存在共同时,deny优先于allow),但是他的使用效果是怎样的呢?设置了所有以后本机还是可以随便访问。
initParams.put("deny", "");
initParams.put("loginUsername","admin");
initParams.put("loginPassword","admin");
initParams.put("resetEnable","false");
bean.setInitParameters(initParams);
return bean;
}
//配置一个web监控的filter
@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean bean=new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
Map<String,String> initParams=new HashMap<>();
initParams.put("exclusions","*.js,*.css,/druid/*");//忽略的资源
bean.setInitParameters(initParams);
bean.setUrlPatterns(Arrays.asList("/*"));
return bean;
}
}
链接
如果数据库的容量太小需要set global max_allowed_packet = 102410241024一下。
设置一个控制分页查询的类,然后把他添加到bean中
/**
* 开启事务管理,但是具体怎么使用呢?
*/
@EnableTransactionManagement
@Configuration
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
// paginationInterceptor.setOverflow(false);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
// paginationInterceptor.setLimit(500);
// 开启 count 的 join 优化,只针对部分 left join
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
return paginationInterceptor;
}
}
在controller写控制分页查询的选项
/**
* 配置分页查询的请求
* 通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx} 占位符可以通过@PathVariable(“xxx“) 绑定到操作方法的入参中。
*/
@ResponseBody
@RequestMapping("/userlist/{id}")
public List<SysUser> listUser(@PathVariable int id){
QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
//queryWrapper.eq("age",23);
IPage<SysUser> page = new Page<>(id,2);
IPage<SysUser> userIPage = userMapper.selectPage(page, queryWrapper);
//查看总共查询到多少条数据
//long total = userIPage.getTotal();
//System.out.println(total);
//把这些数据打印出来
// userIPage.getRecords().forEach(user-> System.out.println(user));
//把查询到的数据用json的格式返回回去
List<SysUser> userList = new LinkedList<>();
userIPage.getRecords().forEach(user-> userList.add(user));
return userList;
}
教程链接
在myaitsplus类上面开启事务管理
@EnableTransactionManagement
然后在想要进行事务管理的地方@Transactional,当这个方法出现错误的时候就会自动执行事务回滚。
如果想要对事务回滚做更加简单操作可以参考下面链接
教程链接
官方文档
从官网上复制下来的,直接使用就可以
package com.hdeasy.project.comment;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class CodeGenerator {
/**
*
* 读取控制台内容
*
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotEmpty(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}
public static void main(String[] args) {
// 代码生成器
AutoGenerator mpg = new AutoGenerator();
// 全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("magician");
gc.setOpen(false);
// gc.setSwagger2(true); 实体属性 Swagger2 注解
mpg.setGlobalConfig(gc);
// 数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/easyapp?serverTimezone=UTC&useUnicode=true&useSSL=false&characterEncoding=utf8");
// dsc.setSchemaName("public");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("root");
mpg.setDataSource(dsc);
// 包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName(scanner("模块名"));
pc.setParent("com.hdeasy.project.test");
mpg.setPackageInfo(pc);
// 自定义配置
InjectionConfig cfg = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};
// 如果模板引擎是 freemarker
String templatePath = "/templates/mapper.xml.ftl";
// 如果模板引擎是 velocity
// String templatePath = "/templates/mapper.xml.vm";
// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();
// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {
// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
return projectPath + "/src/main/resources/mapper/" + pc.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});
/*
cfg.setFileCreate(new IFileCreate() {
@Override
public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
// 判断自定义文件夹是否需要创建
checkDir("调用默认方法创建的目录,自定义目录用");
if (fileType == FileType.MAPPER) {
// 已经生成 mapper 文件判断存在,不想重新生成返回 false
return !new File(filePath).exists();
}
// 允许生成模板文件
return true;
}
});
*/
cfg.setFileOutConfigList(focList);
mpg.setCfg(cfg);
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();
// 配置自定义输出模板
//指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
// templateConfig.setEntity("templates/entity2.java");
// templateConfig.setService();
// templateConfig.setController();
templateConfig.setXml(null);
mpg.setTemplate(templateConfig);
// 策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
strategy.setEntityLombokModel(true);
strategy.setRestControllerStyle(true);
// 公共父类
strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
// 写于父类中的公共字段
strategy.setSuperEntityColumns("id");
strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);
mpg.setTemplateEngine(new FreemarkerTemplateEngine());
mpg.execute();
}
}
使用期间报错(The server time zone value ‘�й���ʱ��‘ is unrecognized or represents more than one time zone.)
在Idea中连接数据库是抛出The server time zone value ‘�й���ʱ��’ is unrecogni错误 原因是因为使用了Mysql Connector/J 6.x以上的版本,然后就报了时区的错误
解决办法是 在配置url的时候不能简单写成:
jdbc:mysql://localhost:3306/yzu
而是要写成 :
jdbc:mysql://localhost:3306/yzu?serverTimezone=UTC
配置一个类继承webmvcConfigurer来配置mvc。可以其中可以配置跨域请求和视图解析器,等等。
@Configuration
public class SpringMVCConfig implements WebMvcConfigurer {
/**
* 配置跨域请求参数
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET","HEAD","POST","PUT","DELETE","OPTIONS")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")//表示文件路径,名为swagger-ui.html的文件
.addResourceLocations("classpath:/META-INF/resources/");//表示开放资源路径
registry.addResourceHandler("/webjars/**")//表示webjars下的所有文件
.addResourceLocations("classpath:/META-INF/resources/webjars/");//表示开放这个路径下的webjars中的所有文件
}
}
@RestController注解相当于@ResponseBody + @Controller合在一起的作用。
下午大概写一个注册数据库的东西来注册新的用户然后在配置redis数据库
创建一个shiroconfig类
@Configuration
public class ShiroConfig {
@Bean
public UserRealm myShiroRealm(){
return new UserRealm();
}
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(securityManager);
//通用配置(跳转登录页面,未授权跳转的页面)
factoryBean.setLoginUrl("/autherror?code=1");//未登录跳转地址,返回json
factoryBean.setUnauthorizedUrl("/autherror?code=2");//未授权跳转地址,返回json
Map<String, String> filterRuleMap = new LinkedHashMap<String, String>();
//设置shiro内置过滤器
/**
* Shiro内置过滤器,可以实现权限相关的拦截器
* 常用的过滤器:
* anon:无需认证就可以访问
* authc: 必须认证才可以访问
* user: 如果使用rememberMe的功能可以直接访问
* perms: 该资源必须得到资源权限可以访问
* role: 该资源必须得到角色权限才可以访问
*/
filterRuleMap.put("/login", "anon");//登陆
filterRuleMap.put("/index.html","anon");
filterRuleMap.put("/","anon");
filterRuleMap.put("/system/register", "anon");//注册
filterRuleMap.put("/autherror", "anon");//跳转地址
filterRuleMap.put("/resources/css/**", "anon");
filterRuleMap.put("/resources/js/**", "anon");
filterRuleMap.put("/resources/fonts/**", "anon");
filterRuleMap.put("/resources/imags/**", "anon");
//不建议使用这个匹配规则,他把resources下面的所有我们设置的静态资源全部展示出来了,那么我们上面的匹配规则已经没有意义了。初衷:我们只是想把某些想要展示的静态资源展示出来。
//filterRuleMap.put("/resources/**","anon");
//放行静态资源
filterRuleMap.put("/static/**", "anon");
filterRuleMap.put("/druid/**","anon");
filterRuleMap.put("/upload/**", "anon");
filterRuleMap.put("/files/**", "anon");
// filterRuleMap.put("/", "anon");
//放行swagger文档
filterRuleMap.put("/swagger-ui.html", "anon");
filterRuleMap.put("/swagger-resources/**", "anon");
filterRuleMap.put("/v2/**", "anon");
filterRuleMap.put("/webjars/**", "anon");
filterRuleMap.put("/logout", "logout");
filterRuleMap.put("/**", "authc");
factoryBean.setFilterChainDefinitionMap(filterRuleMap);
return factoryBean;
}
//
// /**
// * 之后要使用的类需要这个类的存在,所以从这里把他加入到bean中
// * @return
// */
//
// @Bean(name = "lifecycleBeanPostProcessor")
// public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
// return new LifecycleBeanPostProcessor();
// }
//
// /**
// * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证
// * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
// *
// * @return
// */
// @Bean
// @DependsOn({"lifecycleBeanPostProcessor"})//控制bean加载顺序,等到它加载好之后才可以加载
// public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
// DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
// advisorAutoProxyCreator.setProxyTargetClass(true);
// return advisorAutoProxyCreator;
// }
//
// @Bean //Advisor:顾问 //开启对shior注解的支持
// public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
// AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
// authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
// return authorizationAttributeSourceAdvisor;
// }
//
// @Value("${spring.redis.host}")
// private String host;
// @Value("${spring.redis.port}")
// private String port;
// @Value("${spring.redis.timeout}")
// private int timeout;
//
// /**
// * 1.redis的控制器,操作redis
// */
// public RedisManager redisManager() {
// RedisManager redisManager = new RedisManager();
// redisManager.setHost(host + ":" + port);
// redisManager.setTimeout(timeout);
// return redisManager;
// }
//
// /**
// * 2.sessionDao
// */
// public RedisSessionDAO redisSessionDAO() {
// RedisSessionDAO sessionDAO = new RedisSessionDAO();
// sessionDAO.setRedisManager(redisManager());
// return sessionDAO;
// }
//
//
// /**
// * 3.会话管理器
// */
// public DefaultWebSessionManager sessionManager() {
// CustomSessionManager sessionManager = new CustomSessionManager();
// sessionManager.setSessionDAO(redisSessionDAO());
// //设置session会话过期时间,单位:毫秒(在无操作时开始计时)
// sessionManager.setGlobalSessionTimeout(1000*60*20);
// //禁用cookie
// sessionManager.setSessionIdCookieEnabled(false);
// //禁用url重写 url;jsessionid=id
// sessionManager.setSessionIdUrlRewritingEnabled(false);
// return sessionManager;
// }
//
// /**
// * 4.缓存管理器
// */
// public RedisCacheManager cacheManager() {
// RedisCacheManager redisCacheManager = new RedisCacheManager();
// redisCacheManager.setRedisManager(redisManager());
// //设置安全信息的主键字段
// redisCacheManager.setPrincipalIdFieldName("userId");
// return redisCacheManager;
// }
@Bean
public SecurityManager securityManager(UserRealm realm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//设置realm.
securityManager.setRealm(realm);
//将自定义的会话管理器注册到安全管理器中
//securityManager.setSessionManager(sessionManager());
//将自定义的redis缓存管理器注册到安全管理器中
//securityManager.setCacheManager(cacheManager());
return securityManager;
}
}
然后创建一个realm类
public class UserRealm extends AuthorizingRealm {
@Autowired
SysUserMapper userMapper;
//进行授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了授权验证");
return null;
}
//进行认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();//获取用户名
String password = new String((char[]) token.getCredentials());//获取密码
QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username",username);
//根据用户名查找数据源
SysUser user = userMapper.selectOne(queryWrapper);
System.out.println(user.toString());
//账号不存在
if(user == null){
throw new UnknownAccountException("账号或者密码不正确");
}
if(!password.equals(user.getPassword())){
throw new IncorrectCredentialsException("账号或者密码不正确");
}
//判断账号是否存在
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user,password,getName());
//authenticationInfo信息交给shiro,调用login的时候会自动比较doGetAuthenticationInfo(AuthenticationToken token)的token和authenticationInfo
return authenticationInfo;
}
}
最后在controller中控制shiro的验证
@RestController
public class SysLoginController {
@PostMapping(value="/login")
public String login(@RequestParam Map<String,String> loginMap){
String username = loginMap.get("username");
String password = loginMap.get("password");
System.out.println(username+password);
try{
//1.构造登录令牌
//加密密码
password = new Md5Hash(password,username,3).toString();//密码,盐(用户名)就是在生成的加密字符串后面加上用户名,加密次数。
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
//2.获取subject
Subject subject = SecurityUtils.getSubject();
//3.调用login方法,进入realm完成验证
subject.login(token);
//4.获取sessionId
String sessionId =(String) subject.getSession().getId();
System.out.println(sessionId);
//5.返回构造结果
System.out.println("成功");
return "Success";
}catch(Exception e){
System.out.println("失败");
return "fales";
}
}
}
如果前端返回的是json数据就用@RequestBody接收
如果返回的是普通的数据就使用@RequestParam接收
安装redis数据库
在ShiroConfig里面配置的
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private String port;
@Value("${spring.redis.timeout}")
private int timeout;
/**
* 1.redis的控制器,操作redis
*/
public RedisManager redisManager() {
RedisManager redisManager = new RedisManager();
redisManager.setHost(host + ":" + port);
redisManager.setTimeout(timeout);
return redisManager;
}
/**
* 2.sessionDao
*/
public RedisSessionDAO redisSessionDAO() {
RedisSessionDAO sessionDAO = new RedisSessionDAO();
sessionDAO.setRedisManager(redisManager());
return sessionDAO;
}
/**
* 3.会话管理器
*/
public DefaultWebSessionManager sessionManager() {
CustomSessionManager sessionManager = new CustomSessionManager();
sessionManager.setSessionDAO(redisSessionDAO());
//设置session会话过期时间,单位:毫秒(在无操作时开始计时)
sessionManager.setGlobalSessionTimeout(1000*60*20);
//禁用cookie
sessionManager.setSessionIdCookieEnabled(false);
//禁用url重写 url;jsessionid=id
sessionManager.setSessionIdUrlRewritingEnabled(false);
return sessionManager;
}
/**
* 4.缓存管理器
*/
public RedisCacheManager cacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(redisManager());
//设置安全信息的主键字段
redisCacheManager.setPrincipalIdFieldName("userId");
return redisCacheManager;
}
spring:
#配置redis数据库
redis:
#数据库索引默认为零
database: 0
#配置redis服务器地址
host: 127.0.0.1
#默认开启端口号,制作者用一个女星的九键键位做的端口
port: 6379
#链接密码默认为空,可以设置密码么?我再安装的时候就没有找到设置的地方
password:
#链接超时时间(毫秒)
timeout: 1000
jedis:
pool:
#连接池最大连接数,负数表示没有链接限制
max-active: 20
#最大空闲连接数
max-idle: 10
getsessionid的那个类暂时没有看清楚所以先不管他。
教程链接
@Configuration
@EnableSwagger2//开启Swagger2
public class SwaggerConfig {
@Bean
public Docket createRestApi(){
return new Docket(DocumentationType.SWAGGER_2)
.pathMapping("/")
.select()
.apis(RequestHandlerSelectors.basePackage("com.hdeasy.project.controller"))//配置映射和扫描路径
.paths(PathSelectors.any())
.build().apiInfo(new ApiInfoBuilder()
.title("SpringBoot整合Swagger")
.description("SpringBoot整合Swagger,详细信息......")
.version("9.0")
.contact(new Contact("hdeasy","www.baidu.com","[email protected]"))
.license("The Apache License")
.licenseUrl("http://www.baidu.com")
.build());
}
}
@Api注解可以用来标记当前Controller的功能。
@ApiOperation注解用来标记一个方法的作用。
@ApiImplicitParam注解用来描述一个参数,可以配置参数的中文含义,也可以给参数设置默认值,这样在接口测试的时候可以避免手动输入。
如果有多个参数,则需要使用多个@ApiImplicitParam注解来描述,多个@ApiImplicitParam注解需要放在一个@ApiImplicitParams注解中。
需要注意的是,@ApiImplicitParam注解中虽然可以指定参数是必填的,但是却不能代替@RequestParam(required = true),前者的必填只是在Swagger2框架内必填,抛弃了Swagger2,这个限制就没用了,所以假如开发者需要指定一个参数必填,@RequestParam(required = true)注解还是不能省略。
如果参数是一个对象(例如上文的更新接口),对于参数的描述也可以放在实体类中。例如下面一段代码:
@ApiModel
public class User {
@ApiModelProperty(value = “用户id”)
private Integer id;
@ApiModelProperty(value = “用户名”)
private String username;
@ApiOperation("登录用户接口")
@ApiImplicitParams(value = {
@ApiImplicitParam(name = "username", value = "用户名", defaultValue = "caochen"),
@ApiImplicitParam(name = "password", value = "密码", defaultValue = "123456", required = true)
}
)
public String login(@RequestParam Map<String,String> loginMap){
教程链接
Fastjson是一个Java库,可用于将Java对象转换为其JSON表示。它还可用于将JSON字符串转换为等效的Java对象。Fastjson可以处理任意Java对象,包括您没有源代码的预先存在的对象。
阿里官方给的定义是, fastjson 是阿里巴巴的开源JSON解析库,它可以解析 JSON 格式的字符串,支持将 Java Bean 序列化为 JSON 字符串,也可以从 JSON 字符串反序列化到 JavaBean。
速度快
fastjson相对其他JSON库的特点是快,从2011年fastjson发布1.1.x版本之后,其性能从未被其他Java实现的JSON库超越。
使用广泛
fastjson在阿里巴巴大规模使用,在数万台服务器上部署,fastjson在业界被广泛接受。在2012年被开源中国评选为最受欢迎的国产开源软件之一。
测试完备
fastjson有非常多的testcase,在1.2.11版本中,testcase超过3321个。每次发布都会进行回归测试,保证质量稳定。
使用简单
fastjson的 API 十分简洁。
功能完备
支持泛型,支持流处理超大文本,支持枚举,支持序列化和反序列化扩展。
Fastjson入口类是 com.alibaba.fastjson.JSON,主要的 API 是 JSON.toJSONString 和 parseObject。
package com.alibaba.fastjson;
public abstract class JSON {
// Java对象转换为JSON字符串
public static final String toJSONString(Object object);
//JSON字符串转换为Java对象
public static final <T> T parseObject(String text, Class<T> clazz, Feature... features);
}
序列化:
String jsonString = JSON.toJSONString(obj);
反序列化:
VO vo = JSON.parseObject("...", VO.class);
泛型反序列化:
import com.alibaba.fastjson.TypeReference;
List<VO> list = JSON.parseObject("...", new TypeReference<List<VO>>() {
});
Fastjson 处理日期的API很简单,例如:
JSON.toJSONStringWithDateFormat(date, "yyyy-MM-dd HH:mm:ss.SSS")
//使用ISO-8601日期格式
JSON.toJSONString(obj, SerializerFeature.UseISO8601DateFormat);
//全局修改日期格式
JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd";
JSON.toJSONString(obj, SerializerFeature.WriteDateUseDateFormat);
反序列化能够自动识别如下日期格式:
添加好相应的jar包,就是配置好maven然后把logback-spring.xml复制过去
<configuration scan="false" scanPeriod="60 seconds" debug="false">
<property name="LOG_HOME" value="./logs" />
<property name="appName" value="EasyNettyServer">property>
<contextName>${appName}contextName>
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<springProfile name="dev">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ----> [%thread] ---> %-5level %logger{50} - %msg%npattern>
springProfile>
<springProfile name="!dev">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ==== [%thread] ==== %-5level %logger{50} - %msg%npattern>
springProfile>
layout>
appender>
<appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/${appName}.logfile>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.logfileNamePattern>
<MaxHistory>365MaxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>100MBmaxFileSize>
timeBasedFileNamingAndTriggeringPolicy>
rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%npattern>
layout>
appender>
<root level="debug">
<appender-ref ref="stdout" />
<appender-ref ref="appLogAppender" />
root>
configuration>
再写一个类来加载logback配置
@Configuration
@Aspect
@Slf4j
public class LogAspectConfig {
private static final Logger log = LoggerFactory.getLogger(LogAspectConfig.class);
// 定义切点Pointcut
@Pointcut("execution(* com.hdeasy..controller.*Controller.*(..))")//两个..代表所有子目录,最后括号里的两个..代表所有参数
public void logPointCut() {
}
@Before("logPointCut()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 记录下请求内容
log.info("请求地址 : " + request.getRequestURL().toString());
log.info("HTTP METHOD : " + request.getMethod());
// 获取真实的ip地址
//logger.info("IP : " + IPAddressUtil.getClientIpAddress(request));
log.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "."
+ joinPoint.getSignature().getName());
log.info("参数 : " + Arrays.toString(joinPoint.getArgs()));
// loggger.info("参数 : " + joinPoint.getArgs());
}
@Around("logPointCut()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
long startTime = System.currentTimeMillis();
Object ob = pjp.proceed();// ob 为方法的返回值
log.info("耗时 : " + (System.currentTimeMillis() - startTime));
return ob;
}
@AfterReturning(returning = "ret", pointcut = "logPointCut()")// returning的值和doAfterReturning的参数名一致
public void doAfterReturning(Object ret) throws Throwable {
// 处理完请求,返回内容(返回值太复杂时,打印的是物理存储空间的地址)
log.debug("返回值 : " + ret);
}
}
教程链接
教程链接
只要传递json数据就可以处理,后台处理好json就好了
后台给vue传送数据,可以先创建一个Result类,来整合你要发送的信息。然后把Request对象返回回去。