从0开始编写一个spring boot 应用

为什么要使用spring boot?

  • 入门简单,无需编写大量的xml文件来配置应用
  • 内置tomcat,可以生成直接运行的独立jar文件
  • 简化了spring框架一些繁琐的开发方式,提供很多与第三方库的结合

使用eclipse新建一个spring boot工程

1.先在eclipse官网下载一个eclipse EE
2.new -> Maven Project

新建maven项目

3.填写项目信息

选择项目路径
选择quickstart
填写项目默认包名

** 安装spring boot依赖 **
在pom.xml文件添加一点点东西(保存的时候eclipse会自动下载依赖),整个文件如下:

<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>demo</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>demo</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
    </parent>

    <dependencies>

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

    </dependencies>
</project>

路由配置(输出hello world)

在默认生成的App.java文件修改成下面的代码:

package demo.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;


@Controller
@EnableAutoConfiguration
public class App  extends SpringBootServletInitializer implements EmbeddedServletContainerCustomizer {
    
    @RequestMapping("/")
    @ResponseBody
    String home() {
        return "Hello World!";
    }
    
    public void customize(ConfigurableEmbeddedServletContainer container) {  
        container.setPort(8000);  
    }  
    
    public static void main( String[] args ){
        SpringApplication.run(App.class, args);
    }
}

然后我们运行这个文件,在浏览器访问 http://127.0.0.1:8000/ 即可看到效果。

我们来分析这个文件做了什么:

  • 其中main方法的代码就是启动spring boot应用

  • 继承SpringBootServletInitializer 类实现EmbeddedServletContainerCustomizer 接口编写customize方法其实是为了修改spring boot应用监听的端口

  • 类的两个修饰器,@Controller是声明是一个控制器类,@EnableAutoConfiguration大概是自动加载一些bean

  • 我们输出Hello World!的方法也有两个修饰器,@RequestMapping("/")是绑定路由,就是浏览器域名端口后面的一段字符串(不包括get参数),@ResponseBody表示输出字符串到浏览器

也许你会问,我如何限制get或者post方法请求该方法?

@RequestMapping(value="/", method=RequestMethod.POST)
    @ResponseBody
    String home() {
        return "Hello World!";
    }
  • get请求: RequestMethod.GET

  • post请求:RequestMethod.POST

  • put请求: RequestMethod.PUT

  • delete请求: RequestMethod.DELETE

现在可以限制请求方式了,但是我想正则匹配路由又该如何处理呢?

@RequestMapping("/test/{a}/*/{b:\\d+}")
    @ResponseBody
    public String index(@PathVariable int b, @PathVariable String a){
        System.out.println(a);
        System.out.println(b);
        return "test!";
    }

请求 http://127.0.0.1:8000/test/cbd/qwe/123 就可以看到效果!

  • {XXX}来匹配一个任意字符串
  • {xxx:正则表达式}来匹配符合规则的字符串
  • *匹配任意字符串
  • @PathVariable 修饰器把{X}的内容注入方法的参数里面

GET,POST参数获取

@RequestMapping("/test")
    @ResponseBody
    public String test(HttpServletRequest request){
        return request.getParameter("a");
    }

使用HttpServletRequest 对象的getParameter方法即可获取get或者post参数,如果参数不存在则返回null

输出结果设置headers

@RequestMapping(value="/test2", produces="text/plain")
    @ResponseBody
    public String test2(HttpServletResponse response){
        response.setHeader("own", "m");
        return "ok";
    }
  • 修改content-type需要在修饰器的produces参数指定

  • 自定义header调用setHeader方法即可

** 上传和下载文件 **

先看demo代码:


@Bean
    public MultipartConfigElement multipartConfigElement() {
        MultipartConfigFactory factory = new MultipartConfigFactory();
        factory.setMaxFileSize("128KB");
        factory.setMaxRequestSize("128KB");
        return factory.createMultipartConfig();
    }

@RequestMapping(value = "/upload", method = RequestMethod.POST)
    @ResponseBody
    public String upload(@RequestParam("file") MultipartFile file, HttpServletResponse response) throws IOException {
        response.setContentType("application/octet-stream");
        OutputStream os = response.getOutputStream();
        os.write(file.getBytes());
        return "upload!";
    }

其实很简单,接收文件只要在参数加上@RequestParam("file") MultipartFile file。"file"是post文件的变量名字

下载文件,先拿输出response.getOutputStream();。当然记得要设置content-type

模板渲染

这里使用了Thymeleaf模板引擎,其他模板引擎实在搜不出可运行方案。

第一步添加依赖:

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

第二步,在src/main/resources/templates文件夹编写模板文件,以.html结尾

第三步,编写代码返回模板

package demo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class Debug {

    @RequestMapping("/index")
    public String index2(){
        return "web";
    }
    
}

注意返回的字符串不需要加上.html。

静态文件处理

新建一个类(这里是StaticConfig),继承WebMvcConfigurerAdapter类,重写addResourceHandlers方法,代码如下:

package demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class StaticConfig extends WebMvcConfigurerAdapter {
    
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry resourceHandlerRegistry) {
        resourceHandlerRegistry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
        super.addResourceHandlers(resourceHandlerRegistry);
    }
    
}

静态文件放在src/main/resources/static文件夹即可

当然为了让配置生效,我们需要在主类增加注解@ComponentScan("demo.config"),demo.config换成你新建类的包名

允许跨域请求

只需要往入口类添加下面代码:

// 允许跨域请求
    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**").allowedOrigins("*");
            }
        };
    }

数据库操作

1.第一步当然是引入依赖咯,往pom.xml里面添加下面代码:

<!-- 与数据库操作相关的依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!-- 使用数据源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.14</version>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.8</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.2.2</version>
        </dependency>

2.新建一个类用于配置数据库信息

package demo.config;

import java.util.Properties;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

@Configuration
@PropertySource(value="classpath:/demo/config/db_local.properties", ignoreResourceNotFound=true)
public class MyBatisConfig {
    
    @Value("${driverClassName}")
    private String driverClassName;
    
    @Value("${url}")
    private String url;
    
    @Value("${db_username}")
    private String username;
    
    @Value("${password}")
    private String password;
    
    /**
     * 创建数据源
     * @Primary 该注解表示在同一个接口有多个实现类可以注入的时候,默认选择哪一个,而不是让@autowire注解报错 
     */
    @Bean
    //@Primary
    public DataSource getDataSource() throws Exception{
        Properties props = new Properties();
        props.put("driverClassName", this.driverClassName);
        props.put("url", this.url);
        props.put("username", this.username);
        props.put("password", this.password);
        return DruidDataSourceFactory.createDataSource(props);
    }

    /**
     * 根据数据源创建SqlSessionFactory
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource ds) throws Exception{
        SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
        fb.setDataSource(ds);//指定数据源(这个必须有,否则报错)
        //下边两句仅仅用于*.xml文件,如果整个持久层操作不需要使用到xml文件的话(只用注解就可以搞定),则不加
        //fb.setTypeAliasesPackage("com.xxx.firstboot.domain");//指定基包
        //fb.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));//指定xml文件位置
        
        return fb.getObject();
    }
    
}

当然入口类记得加上扫描(@ComponentScan("demo.config"))

上面数据库密码那些是读取了配置文件所以新建一个配置文件(配置文件读取参考下文说明)

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/map?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8
db_username=root
password=root

3.定义操作数据表的接口

import java.util.List;

import org.apache.ibatis.annotations.Select;

public interface SpecialtyMapper {
    
    @Select("select * from specialty where province = #{province};")
    List<demo.dao.SpecialtyDao> getSpecialtyList(String province);
    
}

当然,我们要在入口类用修饰器扫描这些模型类,@MapperScan("demo.mapper")

trip.footprint.dao.SpecialtyDao只是一个普通的java类,用于存储查询到的数据

package demo.dao;

import java.sql.Timestamp;

public class SpecialtyDao {

    private int id;
    private String province;
    private String title;
    private String img;
    private Timestamp create_time;
    private Timestamp update_time;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getImg() {
        return img;
    }

    public void setImg(String img) {
        this.img = img;
    }

    public Timestamp getCreate_time() {
        return create_time;
    }

    public void setCreate_time(Timestamp create_time) {
        this.create_time = create_time;
    }

    public Timestamp getUpdate_time() {
        return update_time;
    }

    public void setUpdate_time(Timestamp update_time) {
        this.update_time = update_time;
    }

}

4.在controller中使用

package demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Debug {
    
    @Autowired
    private demo.mapper.SpecialtyMapper specialtyMapper;
    
    @RequestMapping("/abc")
    @ResponseBody
    public String index(){
        specialtyMapper.getSpecialtyList("广东省");
        return "ok";
    }
    
}

session放于redis

新建一个java类

package trip.footprint.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.session.data.redis.config.ConfigureRedisAction;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;

@Configuration
@EnableRedisHttpSession
@PropertySource(value = "classpath:/trip/footprint/config/redis_bae.properties")
public class SessionConfig {
    @Value("${redisHost}")
    private String redisHost;

    @Value("${redisPort}")
    private int redisPort;

    @Value("${redisPassword}")
    private String redisPassword;

    @Value("${redisDb}")
    private int redisDb;
    
    @Bean
    public static ConfigureRedisAction configureRedisAction() {
        return ConfigureRedisAction.NO_OP;
    }
    
    @Bean
    public JedisConnectionFactory connectionFactory() {
        JedisConnectionFactory factory = new JedisConnectionFactory();
        factory.setHostName(redisHost);
        factory.setPort(redisPort);
        if(redisDb!=-1){
            factory.setDatabase(redisDb);
        }
        if (!redisPassword.equals("")) {
            factory.setPassword(redisPassword);
        }
        return factory;
    }

}

然后记得用@ComponentScan("demo.config")来扫描加载

由于代码读取配置文件,所以新建一个配置文件

redisHost=127.0.0.1
redisPort=6379
redisPassword=
redisDb=0

controller分离成多个文件

其实每一个controller都是一个java类,只是类上面有一个修饰器@Controller或者@RestController。当然记得用@ComponentScan("xxx.xxx")来扫描加载

依赖注入

首先想把类A作为一个变量注入类B,就需要用修饰器@ComponentScan扫描类A和类B的包,同时类A要在类上面加入修饰器@Component,类B变量上面添加修饰器 @Autowired。

类A代码:

package demo.data;

import org.springframework.stereotype.Component;

@Component
public class A {
    
    public String data = "good!";
    
}

类B代码:

package demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Debug {
    
    @Autowired
    private demo.mapper.SpecialtyMapper specialtyMapper;
    
    @Autowired
    private demo.data.A a;
    
    @RequestMapping("/abc")
    @ResponseBody
    public String index(){
        specialtyMapper.getSpecialtyList("广东省");
        return a.data;
    }
    
}

读取配置文件

读取配置文件需要使用修饰器,@PropertySource(value = "classpath:/trip/footprint/config/redis_bae.properties")。classpath后面跟着的是配置文件路径。当然入口类记得用@ComponentScan("demo.config")扫描包。加载配置文件,当然要注入变量,用修饰器@Value("${变量名}")即可注入。代码如下:

package demo.config;

import java.util.Properties;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

@Configuration
@PropertySource(value="classpath:/demo/config/db_local.properties", ignoreResourceNotFound=true)
public class MyBatisConfig {
    
    @Value("${driverClassName}")
    private String driverClassName;
    
    @Value("${url}")
    private String url;
    
    @Value("${db_username}")
    private String username;
    
    @Value("${password}")
    private String password;
    
    /**
     * 创建数据源
     * @Primary 该注解表示在同一个接口有多个实现类可以注入的时候,默认选择哪一个,而不是让@autowire注解报错 
     */
    @Bean
    //@Primary
    public DataSource getDataSource() throws Exception{
        Properties props = new Properties();
        props.put("driverClassName", this.driverClassName);
        props.put("url", this.url);
        props.put("username", this.username);
        props.put("password", this.password);
        return DruidDataSourceFactory.createDataSource(props);
    }

    /**
     * 根据数据源创建SqlSessionFactory
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource ds) throws Exception{
        SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
        fb.setDataSource(ds);//指定数据源(这个必须有,否则报错)
        //下边两句仅仅用于*.xml文件,如果整个持久层操作不需要使用到xml文件的话(只用注解就可以搞定),则不加
        //fb.setTypeAliasesPackage("com.xxx.firstboot.domain");//指定基包
        //fb.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));//指定xml文件位置
        
        return fb.getObject();
    }
    
}

配置文件如下:

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/map?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8
db_username=root
password=root

日志输出

在src/main/resources新建一个文件,写入下面内容:

logging.file=log/myapp.log
logging.level.org.springframework.web=DEBUG
logging.level.root=DEBUG

代码输出日志,代码如下:

package demo.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Debug {
    
    @Autowired
    private demo.mapper.SpecialtyMapper specialtyMapper;
    
    @Autowired
    private demo.data.A a;
    
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    
    @RequestMapping("/abc")
    @ResponseBody
    public String index(){
        logger.debug("ceshi");
        logger.info("对的");
        specialtyMapper.getSpecialtyList("广东省");
        return a.data;
    }
    
}

导出成war

其实主要是修改pom.xml,添加下面代码:

<!-- 打包成war需要 -->
        <dependency>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-tomcat</artifactId>  
            <scope>provided</scope>  
        </dependency>  
<!-- end -->
<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
              <artifactId>maven-war-plugin</artifactId>
              <version>3.0.0</version>
              <configuration>
            <failOnMissingWebXml>false</failOnMissingWebXml>
        </configuration>
            </plugin>
        </plugins>
    </build>

修改pom.xml文件的packaging标签变成<packaging>war</packaging>

然后再用maven build一下:

打包配置
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容