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 { /** * <p> * 读取控制台内容 * </p> */ 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: 10getsessionid的那个类暂时没有看清楚所以先不管他。
教程链接
@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","907153533@qq.com")) .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);反序列化能够自动识别如下日期格式:
ISO-8601日期格式yyyy-MM-ddyyyy-MM-dd HH:mm:ssyyyy-MM-dd HH:mm:ss.SSS毫秒数字毫秒数字字符串.NET JSON日期格式new Date(198293238)添加好相应的jar包,就是配置好maven然后把logback-spring.xml复制过去
<?xml version="1.0" encoding="UTF-8"?> <!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。 scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。 debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 --> <configuration scan="false" scanPeriod="60 seconds" debug="false"> <!-- 定义日志的根目录(这是把日志输出到指定文件:具体的位置是将来jar包所在位置的logs文件夹下) --> <property name="LOG_HOME" value="./logs" /> <!-- 定义日志文件名称 --> <property name="appName" value="EasyNettyServer"></property> <contextName>${appName}</contextName> <!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 --> <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender"> <!-- 日志输出格式: %d表示日期时间, %thread表示线程名, %-5level:级别从左显示5个字符宽度 %logger{50} 表示logger名字最长50个字符,否则按照句点分割。 %msg:日志消息, %n是换行符 --> <layout class="ch.qos.logback.classic.PatternLayout"> <!--1.使用springProfile这个标签的前提是:我们这个日志配置文件的名称必须以spring作为后缀 2.为什么微软推荐使用以spring作为后缀的日志配置文件,因为springProfile可以指定不同开发环境的日志格式。 --> <springProfile name="dev"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ----> [%thread] ---> %-5level %logger{50} - %msg%n</pattern> </springProfile> <springProfile name="!dev"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ==== [%thread] ==== %-5level %logger{50} - %msg%n</pattern> </springProfile> </layout> </appender> <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 --> <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 指定日志文件的名称 --> <file>${LOG_HOME}/${appName}.log</file> <!-- 当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名 TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动 %i:当文件大小超过maxFileSize时,按照i进行文件滚动 --> <fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern> <!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动, 且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是, 那些为了归档而创建的目录也会被删除。 --> <MaxHistory>365</MaxHistory> <!-- 当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy --> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <!-- 日志输出格式: --> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern> </layout> </appender> <!-- logger主要用于存放日志对象,也可以定义日志类型、级别 name:表示匹配的logger类型前缀,也就是包的前半部分 level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERROR additivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出, false:表示只用当前logger的appender-ref,true: 表示当前logger的appender-ref和rootLogger的appender-ref都有效 --> <!-- Spring framework logger 如果需要查看哪些自动配置是否匹配,请将level换成debug--> <!--<logger name="org.springframework" level="info" additivity="false">--> <!--<appender-ref ref="stdout" />--> <!--</logger>--> <!-- root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应, 要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。 --> <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对象返回回去。
