Filecoin video sass vcpkg jboss arm vue学习教程 less用法 android小程序源代码 android常用布局 拼接json字符串 windows杀进程命令 oracle重命名表名 kafka启动命令 linux启动数据库 mysql 选择数据库 python写文件 java正则表达式 java操作mysql java字符串反转 java链接mysql数据库 java结构 java替换字符串 vbscript程序员参考手册 高效能人士的七个习惯下载 din字体 端口关闭工具 华为交换机学习指南 模拟人生2夜生活 音乐狂app 修改ip地址软件 苹果手机添加邮箱 暴力猴插件 vscode全局搜索 完美漂移辅助 pr抖动特效 php验证码 键盘打字手指口诀 su镜像 ps阵列
当前位置: 首页 > 学习教程  > 编程语言

springboot项目实战笔记

2020/10/8 19:34:16 文章标签:

项目总框架 system目录下是整个系统的跳转关系,有登录验证,控制菜单的跳转,和一系列的验证操作 product目录下是用户看到的页面信息,就是管理的产品数据在页面中的显示控制。 common目录是一些组件,帮助用户系统验证…

项目总框架

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 {
    /**
     * <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

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","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的配置

教程链接

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复制过去


<?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);
    }
}

quartz的配置

教程链接

http协议

教程链接

redis操作

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

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

rocktmq

session,request,cookie详解

响应vue

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


本文链接: http://www.dtmao.cc/news_show_250156.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?