springboot项目实战笔记

项目总框架

system目录下是整个系统的跳转关系,有登录验证,控制菜单的跳转,和一系列的验证操作

product目录下是用户看到的页面信息,就是管理的产品数据在页面中的显示控制。

common目录是一些组件,帮助用户系统验证或者配置一些其他的配置。

system目录相关知识学习(需要一些common目录下的组件)

druid池的配置

教程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;
    }
}

mybatisplus

快速生成文档注解

链接

如果数据库的容量太小需要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

SpringMvc的配置

配置一个类继承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合在一起的作用。

shiro的配置

下午大概写一个注册数据库的东西来注册新的用户然后在配置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数据库

安装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的那个类暂时没有看清楚所以先不管他。

swagger UI的配置

教程链接

@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的配置

教程链接

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-dd
  • yyyy-MM-dd HH:mm:ss
  • yyyy-MM-dd HH:mm:ss.SSS
  • 毫秒数字
  • 毫秒数字字符串
  • .NET JSON日期格式
  • new Date(198293238)

slf4j-api的配置

添加好相应的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);
    }
}

quartz的配置

教程链接

http协议

教程链接

redis操作

后台处理前端VUE传送过来的json数据

只要传递json数据就可以处理,后台处理好json就好了

rocktmq

session,request,cookie详解

响应vue

后台给vue传送数据,可以先创建一个Result类,来整合你要发送的信息。然后把Request对象返回回去。

你可能感兴趣的:(java,java,spring)