uniquejava / blog

My notes regarding the vibrating frontend :boom and the plain old java :rofl.
Creative Commons Zero v1.0 Universal
11 stars 5 forks source link

spring boot #96

Open uniquejava opened 7 years ago

uniquejava commented 7 years ago

下载spring tool suite 阅读: Building an Application with Spring Boot

重拾后端之Spring Boot

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.icyper</groupId>
    <artifactId>girl</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>girl</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
uniquejava commented 6 years ago

Integrate with websphere liberty

see http://www.adeveloperdiary.com/java/spring-boot/deploy-spring-boot-application-ibm-liberty-8-5/

以上步骤巨TMD的复杂,spring官网上提供了更简单的将jar转换成war的步骤, 可以直接部署到WebSphere Liberty

在这: https://spring.io/guides/gs/convert-jar-to-war/

also see top posts on that page.

打成war包

https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-create-a-deployable-war-file

Integrate JSP View

Spring Boot – JSP View Example 写得非常详细.

Spring: @Component versus @Bean

https://stackoverflow.com/questions/10604298/spring-component-versus-bean

Spring Boot CORS

https://spring.io/guides/gs/rest-service-cors/

https://stackoverflow.com/questions/42874351/spring-boot-enabling-cors-by-application-properties

综合以上两篇, 最终我的配置如下:

@SpringBootApplication
public class SpringBootWebApplication extends SpringBootServletInitializer {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/api/**").allowedOrigins("*");
            }
        };
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(SpringBootWebApplication.class);
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(SpringBootWebApplication.class, args);
    }
}
uniquejava commented 6 years ago

common

区分不同的环境 如果在本地只需要在Eclipse中加上启动参数-Dspring.profiles.active=dev就行 spring boot会先取application.properties的内容. 然后取application-dev.proertpies文件的内容, 同名的key的值会被覆盖.

如果某个key只在application-dev.properties中定义了,会报错:java.lang.IllegalArgumentException: Could not resolve placeholder

让spring忽略之, 在启动类中加如下配置即可.

@Bean
    public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
        PropertySourcesPlaceholderConfigurer c = new PropertySourcesPlaceholderConfigurer();
        c.setIgnoreUnresolvablePlaceholders(true);
        return c;
    }

init db

https://stackoverflow.com/questions/30732314/execute-sql-file-from-spring-jdbc-template

References

https://stackoverflow.com/questions/31865442/how-to-set-default-environment-in-spring-boot

uniquejava commented 6 years ago

Integrate SQLite (多数据源)

POM

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.xerial</groupId>
            <artifactId>sqlite-jdbc</artifactId>
        </dependency>

去掉ds自动配置

@SpringBootApplication
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})

建一个相关的factory bean

package com.ibm.wex.utils;

import java.io.File;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.stereotype.Component;

/**
 * sqlite db factory to support multiple database for different collections.
 * 
 * @author cyper
 *
 */
@Component
public class SqliteDbFactoryBean implements FactoryBean<JdbcTemplate> {

    final static Logger logger = LoggerFactory.getLogger(SqliteDbFactoryBean.class);

    private Map<String, JdbcTemplate> cache = new ConcurrentHashMap<>();

    private DataSourceBuilder dataSourceBuilder;

    private String key;

    @Value("${db.path}")
    private String dbPath;

    @PostConstruct
    public void initClient() {
        this.dataSourceBuilder = DataSourceBuilder.create().driverClassName("org.sqlite.JDBC");
    }

    @Override
    public JdbcTemplate getObject() throws Exception {
        logger.info("get db instance for key {}", key);

        if (!cache.containsKey(key)) {
            logger.info("create a new db instance for {}", key);
            logger.info("db name is {}", key);

            File dbDir = new File(dbPath);
            if (!dbDir.exists()) {
                dbDir.mkdirs();
            }

            File dbFile = new File(dbDir, key + ".db");
            boolean dbExists = dbFile.exists();

            String url = String.format("jdbc:sqlite:%s", dbFile.getAbsolutePath());
            logger.info(url);
            // note this line will create an empty db file.
            DataSource ds = dataSourceBuilder.url(url).build();

            if (!dbExists) {
                Resource resource = new ClassPathResource("scripts/db-init.sql");
                ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(resource);
                databasePopulator.execute(ds);
            }

            cache.put(key, new JdbcTemplate(ds));
        }

        return cache.get(key);
    }

    @Override
    public Class<?> getObjectType() {
        return JdbcTemplate.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    public void setKey(String key) {
        this.key = key;
    }

}
uniquejava commented 6 years ago

启动后

@EventListener(ApplicationReadyEvent.class)
public void doSomethingAfterStartup() {
    System.out.println("hello world, I have just started up");
}

详见: Running code after Spring Boot starts

那么我要将properties中的值注入到utils类的一个静态变量中, 目前我是这么做的

@SpringBootApplication
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class SpringBootWebApplication extends SpringBootServletInitializer {
    final static Logger logger = LoggerFactory.getLogger(SpringBootWebApplication.class);

    @Value("${some.var}")
    private String someVar;

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/api/**").allowedOrigins("*").allowedMethods("GET", "POST", "PUT", "DELETE")
                        .allowCredentials(false).maxAge(3600);
            }
        };
    }

    @EventListener(ApplicationReadyEvent.class)
    public void doSomethingAfterStartup() {
        MyUtils.setSomeVar(someVar);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(SpringBootWebApplication.class);
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(SpringBootWebApplication.class, args);
    }
}
uniquejava commented 6 years ago

Test Service Layer

修改pom加上

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

新建测试类(在类名上alt+enter选择意图为create test)

@RunWith(SpringRunner.class)
@ActiveProfiles("cyper")
@SpringBootTest
public class XxxServiceTest {
    private final static Logger logger = LoggerFactory.getLogger(XxxServiceTest.class);
    @Autowired
    private XxxService xxxService;

    @Before
    public void setUp() {
    }

    @Test
    public void saveXxx() {
        // ...
        Assert.assertEquals("There should be 2 fields create.", 2, fields.size());
    }

}
uniquejava commented 6 years ago

文件上传

spring.http.multipart.maxFileSize=128MB
spring.http.multipart.maxRequestSize=128MB

注意

  1. spring boot 1.3, 1.4, 2.x 关于这块的配置各不相同.
  2. 这两个参数必须同时设置, 多文件同时上传时, 第二个参数值大约为第一个参数*文件数.

见: I am trying to set maxFileSize but it is not honored