记录Spring Boot小项目的一些坑

现有一个用spring boot的后台项目,项目开发rest端口与前端交互,使用Jython调用本地python代码。项目基于IDEA开发,部署在windows系统中。

第一个坑:跨域请求

前端使用ajax请求后台接口,后台返回json数据。后台独立测试(curl、restlet)没问题,前端出现报错跨域问题。

首先我们试图在ajax请求中增加dataType并设定为jsonp,结果没有报跨域问题,返回直接进入了error,状态码200,一些博客认为是后台数据不够严谨,不是严格的json格式,然后并不是。

$.ajax({ //请求方式
    type: "GET",
    contentType: "application/json;charset=UTF-8",//请求的媒体类型
    url: "http://127.0.0.1:8088/search?carId=" + carId, // 请求地址
    dataType: "jsonp",

    success: function (result) {
       ...

最终解决问题的办法是通过后台来支持跨域,这里还有一个小坑,在springboot1和springboot2中支持跨域的处理方式不相同。

在springboot2之下,我们可以通过如下两步来增加跨域支持。

1、写一个配置类,实现增加跨域映射

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
public class CorsConfig implements WebMvcConfigurer {

    public void addCorsMappings(CorsRegistry registry){
        registry.addMapping("/**")
                //设置允许跨域请求的域名
                .allowedOrigins("*")
                //是否允许证书 不再默认开启
                .allowCredentials(true)
                //设置允许的方法
                .allowedMethods("*")
                //跨域允许时间
                .maxAge(3600);
    }
}

2、利用注解配置Controller

@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/")
public class IndexController {
    private AlgorithmModel algorithmModel;
    private FileModel fileModel;

    @CrossOrigin(origins = "http://localhost:63342")
    @GetMapping(value = "/search")
    public Result search(@RequestParam String carId)
    {
        List<Route> routes = null;
        // check if file exists
        if(fileModel.fileExists(carId)){
            routes = fileModel.genRoutes(carId);
        }else{
            if(algorithmModel.call(carId) != null){
                routes = fileModel.genRoutes(carId);
            }else{
                return Result.fail("1");
            }
        }
        return Result.success("0", routes);
    }
}

PS:注解的位置比较灵活

  • 可以直接注解整个类
  • 可以将部分注解类,然后将另一部分注解方法上
  • 或者直接注解方法

第二个坑:打包运行时Jython下的PythonInterpreter报错

因为要调用外部的python代码,我使用了Jython。将PythonInterpreter设置为bean,并组装进其他的bean中。

@Bean
public PythonInterpreter getPythonInterpreter() {
    PythonInterpreter pyInterpreter = new PythonInterpreter();
    return pyInterpreter;
}

在idea中运行的时候没有任何问题,打包运行时报错如下:

...
Error starting ApplicationContext. To display the conditions report re-run your application with ‘debug‘ enabled.
2019-06-24 16:56:04.915 ERROR 51338 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘indexController‘ defined in URL [jar:file:/Users/zhengshuangxi/Desktop/car/vehicle-web-0.0.2-SNAPSHOT.jar!/BOOT-INF/classes!/cn/xidian/sxzheng/vehicleweb/controller/IndexController.class]: Unsatisfied dependency expressed through constructor parameter 0;
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘getAlgorithmModel‘ defined in class path resource [cn/xidian/sxzheng/vehicleweb/config/MyConfig.class]: Bean instantiation via factory method failed;
nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [cn.xidian.sxzheng.vehicleweb.model.AlgorithmModel]: Factory method ‘getAlgorithmModel‘ threw exception;
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘getPythonInterpreter‘ defined in class path resource [cn/xidian/sxzheng/vehicleweb/config/MyConfig.class]: Bean instantiation via factory method failed;
nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.python.util.PythonInterpreter]: Factory method ‘getPythonInterpreter‘ threw exception; nested exception is ImportError: Cannot import site module and its dependencies: No module named site
...

根据报错信息可以得知 getPythonInterpreter 方法报错,报错信息为 "Cannot import site module and its dependencies: No module named site" ,这里的原因是没有site模块,解决办法就是修改getPythonInterpreter方法

@Bean
public PythonInterpreter getPythonInterpreter() {
    Properties props = new Properties();
    props.put("python.home", "../jython-2.7.0");
    props.put("python.console.encoding", "UTF-8");
    props.put("python.security.respectJavaAccessibility", "false");
    props.put("python.import.site", "false");
    Properties preprops = System.getProperties();
    PythonInterpreter.initialize(preprops, props, new String[0]);
    PythonInterpreter pyInterpreter = new PythonInterpreter();
    return pyInterpreter;
}

修改代码处理之后,site的问题没有了,但是后来又报错“os模块找不见”。这些问题的原因主要是因为在java中使用Jython运行python程序时候,它的搜索路径需要手动设置。而且Jython有个致命的弱点,就是它支持的库太少了,像一些科学计算库numpy等都比较麻烦,因此我后来改用Runtime执行python文件,同时我也强烈推荐大家使用Runtime执行外部程序,并通过io流收集结果。

    public String call(String carId){
        Process process;
        String command = "python3 " + pythonFilePath + " " + carId;
        System.out.println(command);
        String result = "";
        try{
            process = Runtime.getRuntime().exec(command);
            BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line = null;
            while((line = in.readLine()) != null){
                result = result.concat(line);
            }
            in.close();
            process.waitFor();
        }catch(IOException e){
            e.printStackTrace();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        return result;
    }

第三个坑:读取外部属性文件

因为后台开发完成之后需要打包运行在别的机器上,因此关于python程序位置的设置,一些外部的参数设置就必须通过外部配置文件来完成,写入工程里面的application.properties不能进行修改,所以必须要实现可以读取外部属性配置文件。每次修改属性文件后重新启动程序就可以生效。

像图中的application.properties文件最终是打包到jar中的,无法进行修改。我们需要类似右边的情况,在config中对配置文件进行随时修改,然后可以通过重新运行jar文件来使得修改生效。

开发阶段,我们可以通过@PropertySource注解来使用外部的配置文件,然后通过@Value注解取配置文件中的参数。

打包部署后,我们可以直接在jar的当前目录下新建config文件夹,并新建application.properties文件,外部文件的优先级大于内部配置文件,因此我们可以手动修改application.properties来实现配置参数在生产环境中的修改。

原文地址:https://www.cnblogs.com/zhengshuangxi/p/11079420.html

时间: 2024-10-13 14:12:29

记录Spring Boot小项目的一些坑的相关文章

部署spring boot + Vue遇到的坑(权限、刷新404、跨域、内存)

部署spring boot + Vue遇到的坑(权限.刷新404.跨域.内存) 项目背景是采用前后端分离,前端使用vue,后端使用springboot. 工具 工欲善其事必先利其器,我们先找一个操作Linux系统的工具极力推荐FinalShell. 一眼看过去是不是感觉很方便,对内存.CPU的监控也可以实时看到,访问目录更是方便,对于Linux小白来说简直是神兵利器. 好了,我要开始入坑了. 问题一:权限不够 把vue包放到tomcat->webapps->ROOT目录下. 启动tomcat:

初学spring boot踩过的坑

一.搭建spring boot环境 maven工程 pom文件内容 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-

Spring Boot项目的Logback配置文件使用yaml格式

1.普通的Spring项目使用logback默认用properties文件做为配置变量. 2.如果非要用yaml文件,那么可以转成Spring Boot项目,天生无缝结合 3.没办法,如果项目配置文件用了yaml,那么你的logback只能自己另开properties文件进行单独配置 以下是基于Spring Boot的yaml配置文件示例: application.yml: # 日志配置 为空为项目跟目录下的logs 或者指定已经存在的目录 log: path: /data/weblog/bus

Spring Boot Admin 使用的坑

这几天公司需要部署SpringBootAdmin监控,用来时刻关注微服务的状态 按照官网的操作非常简单: 1. 添加依赖到pom.xml <dependency> <groupId>de.codecentric</groupId> <artifactId>spring-boot-admin-server</artifactId> <version>${springboot.admin.version}</version>

spring boot 枚举使用的坑

java 枚举的功能挺多,但是坑更多,使用的时候要注意.如下面这个枚举. @Getter @AllArgsConstructor public enum EnumExpenseType implements BaseEnum { 小欢喜(1), 大欢喜(2); private final int value; } 咋一看,没什么问题,但是具体使用过程中,总是会出问题.原因就是这个枚举没有按照从0开始索引,除此之外即使从0开始,中间有断的索引也会有问题.主要出现在以下方面: 1. 在control

Javascript学习记录——一次小项目的总结

这几天都忙着上课还有准备项目,没有时间写博客,今天总是完成了项目的评比,有点失落,有点感悟. 背景:博主是传智博客的培训生,学完了html,css,以及js特效,班级共84人,项目分为8组,博主有幸担任第8组组长. 项目概况:每个组各自以一个网站为模板进行模仿,页面为非静态页面,时间为1周,包括上课时间.(博主用的原生js) 项目完成过程: 1.接到任务当天,博主便组织小组成员在晚自习时间进行一次简单的讨论,然后发布任务,每人选择两个自己中意的网站,并说明理由,第二天将要写的网站定下来. 2.次

记录Spring Boot大坑一个,在bean中如果有@Test单元测试,不会注入成功

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 原文地址:https://www.cnblogs.com/zipon/p/9891031.html

Spring Boot 之日志记录

Spring Boot 之日志记录 Spring Boot 支持集成 Java 世界主流的日志库. 如果对于 Java 日志库不熟悉,可以参考:细说 Java 主流日志工具库 关键词: log4j, log4j2, logback, slf4j 日志格式 控制台输出 彩色打印 文件输出 日志级别 日志组 日志配置文件 Spring Boot 中的日志配置 源码 引申和引用 Spring Boot 内部日志全部使用 Commons Logging 记录,但保留底层日志实现.为 Java Util

使用 Spring Boot 快速构建 Spring 框架应用

Spring Boot 的目的在于快速创建可以独立运行的 Spring 应用.通过 Spring Boot 可以根据相应的模板快速创建应用并运行.Spring Boot 可以自动配置 Spring 的各种组件,并不依赖代码生成和 XML 配置文件.Spring Boot 可以大大提升使用 Spring 框架时的开发效率. Why we choose Spring Boot ? Spring 框架对于很多 Java 开发人员来说都不陌生.自从 2002 年发布以来,Spring 框架已经成为企业应