美文网首页
springboot

springboot

作者: 提笔忘字_波 | 来源:发表于2019-05-05 11:17 被阅读0次

参考文档
https://www.cnblogs.com/ityouknow/p/5662753.html

1、Idea 构建项目

1、选择 File -> New —> Project... 弹出新建项目的框
2、选择 Spring Initializr,Next 也会出现上述类似的配置界面,Idea 帮我们做了集成
3、填写相关内容后,点击 Next 选择依赖的包再点击 Next,最后确定信息无误点击 Finish。

引入 Web 模块

1、pom.xml中添加支持web的模块:

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
pom.xml文件中默认有两个模块:
spring-boot-starter:核心模块,包括自动配置支持、日志和YAML;
spring-boot-starter-test:测试模块,包括JUnit、Hamcrest、Mockito。

2、编写controller内容

@RestController
public class HelloWorldController {
    @RequestMapping("/hello")
    public String index() {
        return "Hello World";
    }
}
@RestController的意思就是controller里面的方法都以json格式输出,不用再写什么jackjson配置的了!

3、如何做单元测试
打开的src/test/下的测试入口,编写简单的http请求来测试;使用mockmvc进行,利用MockMvcResultHandlers.print()打印出执行结果

 @RunWith(SpringRunner.class)
  @SpringBootTest

public class HelloWorldControlerTests {
    private MockMvc mvc;
    @Before
    public void setUp() throws Exception {
        mvc = MockMvcBuilders.standaloneSetup(new HelloWorldController()).build();
    }
    @Test
    public void getHello() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/hello").accept(MediaType.APPLICATION_JSON))
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();
    }
}

4、热加载

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
   </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <fork>true</fork>
            </configuration>
        </plugin>
   </plugins>
</build>

2、搭建简单的RESTfull API接口项目

1、引入依赖
spring-boot-start-web:搭建springboot项目
spring-boot-devtools : springboot工具

2、代码实现

pom.xml文件

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.0.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-devtools</artifactId>
        </dependency>
    </dependencies>

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

实体类

import java.util.Date;
/**
 * 实体类
 * 
 * @author wujing
 */
public class User {
    private int id;
    private String name;
    private Date date;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
}

controller层

@RestController //Spring4之后新加入的注解,原来返回json需要@ResponseBody@Controller配合。即@RestController是@ResponseBody和@Controller的组合注解。
@RequestMapping(value = "/index")
public class IndexController {
    @RequestMapping
    public String index() {
        return "hello world";
    }
    // @RequestParam 简单类型的绑定,可以出来get和post
    @RequestMapping(value = "/get")
    public HashMap<String, Object> get(@RequestParam String name) {
        HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("title", "hello world");
        map.put("name", name);
        return map;
    }
    // @PathVariable 获得请求url中的动态参数
    @RequestMapping(value = "/get/{id}/{name}")
    public User getUser(@PathVariable int id, @PathVariable String name) {
        User user = new User();
        user.setId(id);
        user.setName(name);
        user.setDate(new Date());
        return user;
    }
}

使用MockMvc测试

需要引入spring-boot-starter-test这个jar包

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootDemo21ApplicationTests {
    private MockMvc mvc;
    @Before
    public void setup() {
        this.mvc = MockMvcBuilders.standaloneSetup(new IndexController()).build();
    }
    @Test
    public void contextLoads() throws Exception {
        RequestBuilder request = get("/index");
    mvc.perform(request).andExpect(status().isOk()).andExpect(content().string("hello world"));
        request = get("/index/get").param("name", "无境");
        mvc.perform(request).andExpect(status().isOk()).andExpect(content().string("{\"name\":\"无境\",\"title\":\"hello world\"}"));
    }
}

3、配置文件详解--Properties和YAML

1)配置文件的生效顺序,会对值进行覆盖

1. @TestPropertySource 注解
2. 命令行参数
3. Java系统属性(System.getProperties())
4. 操作系统环境变量
5. 只有在random.*里包含的属性会产生一个RandomValuePropertySource
6. 在打包的jar外的应用程序配置文件(application.properties,包含YAML和profile变量)
7. 在打包的jar内的应用程序配置文件(application.properties,包含YAML和profile变量)
8. 在@Configuration类上的@PropertySource注解
9. 默认属性(使用SpringApplication.setDefaultProperties指定)

  1. 读取使用注解:@Value(value = "${roncoo.secret}")


    image.png

3)Application属性文件,按优先级排序,位置高的将覆盖位置低的

1. 当前目录下的一个/config子目录
2. 当前目录
3. 一个classpath下的/config包
4. classpath根路径(root)
这个列表是按优先级排序的(列表中位置高的将覆盖位置低的)

4)配置应用端口和其他配置的介绍

#端口配置:
server.port=8090
#时间格式化
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
#时区设置
spring.jackson.time-zone=Asia/Chongqing

使用YAML代替Properties -> 冒号后要加个空格

5)多环境配置
1、创建application.properties、application-dev.properties、application-prod.properties、application-test.properties文件,文件内容如下:

#主配置文件,配置了这个会优先读取里面的属性覆盖主配置文件的属性
spring.profiles.active=dev
#时间格式化
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
#时区设置
spring.jackson.time-zone=Asia/Chongqing

6)两种配置方式的比较

1. Properties配置多环境,需要添加多个配置文件,YAML只需要一个配件文件
2.书写格式的差异,yaml相对比较简洁,优雅
3. YAML的缺点:不能通过@PropertySource注解加载。如果需要使用@PropertySource注解的方式加载值,那就要使用properties文件。

java -jar myapp.jar --spring.profiles.active=dev


4、 日志配置

支持日志框架:Java Util Logging, Log4J2 and Logback,默认是使用logback
配置方式:默认配置文件配置和引用外部配置文件配置

1、默认配置文件配置(不建议使用:不够灵活,对log4j2等不够友好)

# 日志文件名,比如:roncoo.log,或者是 /var/log/roncoo.log
logging.file=roncoo.log 
# 日志级别配置,比如: logging.level.org.springframework=DEBUG
logging.level.*=info
logging.level.org.springframework=DEBUG

2、引用外部配置文件

spring boot默认会加载classpath:logback-spring.xml或者classpath:logback-spring.groovy

使用自定义配置文件,配置方式为:
logging.config=classpath:logback-roncoo.xml
注意:不要使用logback这个来命名,否则spring boot将不能完全实例化

1.使用基于spring boot的配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="org.springframework.web" level="DEBUG"/>
</configuration>

3、log4j配置
3.1去除logback的依赖包,添加log4j2的依赖包

<dependency>
    <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-logging</artifactId>
            </exclusion>
        </exclusions>
</dependency>
<!-- 使用log4j2 -->
<dependency>
        <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>

3.2在classpath添加log4j2.xml或者log4j2-spring.xml(spring boot 默认加载)

应用自定义配置

logging.config=classpath:log4j2-dev.xml
3.3 log4j2配置文件内容

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <properties>
        <!-- 文件输出格式 -->
        <property name="PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} |-%-5level [%thread] %c [%L] -| %msg%n</property>
    </properties>
    <appenders>
        <Console name="CONSOLE" target="system_out">
            <PatternLayout pattern="${PATTERN}" />
        </Console>
    </appenders>
    <loggers>
        <logger name="com.roncoo.education" level="debug" />
        <root level="info">
            <appenderref ref="CONSOLE" />
        </root>
    </loggers>
</configuration>

3.4 java中引入

private static final Logger logger = LoggerFactory.getLogger(IndexController.class);
logger.debug("this is a log test, debug");
logger.info("this is a log test, info");

5、错误处理

1)Spring Boot 将所有的错误默认映射到/error, 实现ErrorController

@Controller
@RequestMapping(value = "error")
public class BaseErrorController implements ErrorController {
private static final Logger logger = LoggerFactory.getLogger(BaseErrorController.class);
    @Override
    public String getErrorPath() {
        logger.info("出错啦!进入自定义错误控制器");
        return "error/error";
    }
    @RequestMapping
    public String error() {
        return getErrorPath();
    }
}

2)添加自定义的错误页面

html静态页面:在resources/public/error/ 下定义
如添加404页面: resources/public/error/404.html页面,中文注意页面编码
模板引擎页面:在templates/error/下定义
如添加5xx页面: templates/error/5xx.ftl
注:templates/error/ 这个的优先级比较 resources/public/error/高

3)使用注解@ControllerAdvice

       /**
     * 统一异常处理
     * 
     * @param exception
     *            exception
     * @return
     */
    @ExceptionHandler({ RuntimeException.class })
    @ResponseStatus(HttpStatus.OK)
    public ModelAndView processException(RuntimeException exception) {
        logger.info("自定义异常处理-RuntimeException");
        ModelAndView m = new ModelAndView();
        m.addObject("exception", exception.getMessage());
        m.setViewName("error/500");
        return m;
    }
    /**
     * 统一异常处理
     * 
     * @param exception
     *            exception
     * @return
     */
    @ExceptionHandler({ Exception.class })
    @ResponseStatus(HttpStatus.OK)
    public ModelAndView processException(Exception exception) {
        logger.info("自定义异常处理-Exception");
        ModelAndView m = new ModelAndView();
        m.addObject("roncooException", exception.getMessage());
        m.setViewName("error/500");
        return m;
    }

6、Servlets, Filters, listeners

Web开发使用 Controller 基本上可以完成大部分需求,但是我们还可能会用到 Servlet、 >Filter、 Listener 等等
1) spring boot 中的三种实现方式
方法一:通过注册 ServletRegistrationBean、 FilterRegistrationBean 和 ServletListenerRegistrationBean 获得控制

/**
* 自定义 servlet *
* @author wujing 
*/
public class CustomServlet extends HttpServlet {
/** *
   */
  private static final long serialVersionUID = 1L;
  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
         throws ServletException, IOException {
     System.out.println("servlet get method");
     doPost(request, response);
}
  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
         throws ServletException, IOException {
     System.out.println("servlet post method");
     response.getWriter().write("hello world");
} }
/**
* 自定义 filter *
* @author wujing 
*/
public class CustomFilter implements Filter {
  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
     System.out.println("init filter");
  }
  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
         throws IOException, ServletException {
     System.out.println("do filter");
     chain.doFilter(request, response);
}
  @Override
  public void destroy() {
     System.out.println("destroy filter");
  }
}
/**
* 自定义 listener *
* @author wujing */
public class CustomListener implements ServletContextListener {
  @Override
  public void contextInitialized(ServletContextEvent sce) {
     System.out.println("contextInitialized");
  }
  @Override
  public void contextDestroyed(ServletContextEvent sce) {
     System.out.println("contextDestroyed");
  }
}
@Bean
  public ServletRegistrationBean servletRegistrationBean() {
     return new ServletRegistrationBean(new CustomServlet(), "/roncoo");
  }
  @Bean
  public FilterRegistrationBean filterRegistrationBean() {
     return new FilterRegistrationBean(new CustomFilter(), servletRegistrationBean());
  }
  @Bean
  public ServletListenerRegistrationBean<CustomListener> servletListenerRegistrationBean() {
return new ServletListenerRegistrationBean<CustomListener>(new CustomListener()); 
}

方法二:通过实现 ServletContextInitializer 接口直接注册

public class SpringBootDemo102Application implements ServletContextInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        servletContext.addServlet("customServlet", new CustomServlet()).addMapping("/roncoo");
        servletContext.addFilter("customFilter", new CustomFilter())
            .addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST), true, "customServlet");
        servletContext.addListener(new CustomListener());
    }
    public static void main(String[] args) {
        SpringApplication.run(SpringBootDemo102Application.class, args);
    }
}

方法三:在 SpringBootApplication 上使用@ServletComponentScan 注解后,直接通过@WebServlet、 @WebFilter、@WebListener 注解自动注册

文件一:
@ServletComponentScan
@SpringBootApplication
public class SpringBootDemo103Application {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootDemo103Application.class, args);
    }
}
CustomFilter:
@WebFilter(filterName = "customFilter", urlPatterns = "/*")
public class CustomFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init filter");
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("do filter");
        chain.doFilter(request, response);
    }
    @Override
    public void destroy() {
        System.out.println("destroy filter");
    }
}
CustomListener:
@WebListener
public class CustomListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("contextInitialized");
    }
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("contextDestroyed");
    }
}
CustomServlet:
@WebServlet(name = "customServlet", urlPatterns = "/roncoo")
public class CustomServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("servlet get method");
        doPost(request, response);
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("servlet post method");
        response.getWriter().write("hello world");
        response.flushBuffer();
    }
}

HttpServlet
Filter
ServletContextListener

7、CORS 支持

全局配置:
@Configuration
public class CustomCorsConfiguration {
  @Bean
  public WebMvcConfigurer corsConfigurer() {
     return new WebMvcConfigurerAdapter() {
         @Override
         public void addCorsMappings(CorsRegistry registry) {
              registry.addMapping("/api/**").allowedOrigins("http://localhost:8080");
  } };
} }
/**
* 全局设置
*
* @author wujing */
@Configuration
public class CustomCorsConfiguration2 extends WebMvcConfigurerAdapter {
  @Override
  public void addCorsMappings(CorsRegistry registry) {
     registry.addMapping("/api/**").allowedOrigins("http://localhost:8080");
  }
}
细粒度配置

/**
* @author wujing
*/
@RestController
@RequestMapping(value = "/api", method = RequestMethod.POST)
public class ApiController {
    @CrossOrigin(origins = "http://localhost:8080")
    @RequestMapping(value = "/get")
    public HashMap<String, Object> get(@RequestParam String name) {
        HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("title", "hello world");
        map.put("name", name);
        return map;
    } 
}

8、文件上传

@Controller
@RequestMapping(value = "/file")
public class FileController {
    private static final Logger logger = LoggerFactory.getLogger(FileController.class);
    @RequestMapping(value = "upload")
    @ResponseBody
    public String upload(@RequestParam("roncooFile") MultipartFile file) {
        if (file.isEmpty()) {
            return "文件为空";
        }
        // 获取文件名
        String fileName = file.getOriginalFilename();
        logger.info("上传的文件名为:" + fileName);
        // 获取文件的后缀名
        String suffixName = fileName.substring(fileName.lastIndexOf("."));
        logger.info("上传的后缀名为:" + suffixName);
        // 文件上传路径
        String filePath = "./images/";
        // 解决中文问题,liunx下中文路径,图片显示问题
        // fileName = UUID.randomUUID() + suffixName;
        File dest = new File(filePath + fileName);
        // 检测是否存在目录
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }
        try {
            file.transferTo(dest);
            return "上传成功";
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "上传失败";
    }
}

浏览器内容:
<form method="POST" enctype="multipart/form-data" action="/file/upload"> 
     文件:<input type="file" name="roncooFile" />
      <input type="submit" value="上传" />
</form>

9、事务

Transactional

10 、 发送邮件

1、添加依懒

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

2、配置

# mail
spring.mail.host: smtp.exmail.qq.com
spring.mail.username:fengyw@roncoo.com,service@roncoo.com,education@roncoo.com
spring.mail.password:
spring.mail.properties.mail.smtp.auth: true

3、代码实现

/**
 * 实现多账号,轮询发送
 * 
 * @author wujing
 */
@Configuration
@EnableConfigurationProperties(MailProperties.class)
public class RoncooJavaMailSenderImpl extends JavaMailSenderImpl implements JavaMailSender {
    private ArrayList<String> usernameList;
    private ArrayList<String> passwordList;
    private int currentMailId = 0;
    private final MailProperties properties;
    public RoncooJavaMailSenderImpl(MailProperties properties) {
        this.properties = properties;

        // 初始化账号
        if (usernameList == null)
            usernameList = new ArrayList<String>();
        String[] userNames = this.properties.getUsername().split(",");
        if (userNames != null) {
            for (String user : userNames) {
                usernameList.add(user);
            }
        }
        // 初始化密码
        if (passwordList == null)
            passwordList = new ArrayList<String>();
        String[] passwords = this.properties.getPassword().split(",");
        if (passwords != null) {
            for (String pw : passwords) {
                passwordList.add(pw);
            }
        }
    }
    @Override
    protected void doSend(MimeMessage[] mimeMessage, Object[] object) throws MailException {

        super.setUsername(usernameList.get(currentMailId));
        super.setPassword(passwordList.get(currentMailId));

        // 设置编码和各种参数
        super.setHost(this.properties.getHost());
        super.setDefaultEncoding(this.properties.getDefaultEncoding().name());
        super.setJavaMailProperties(asProperties(this.properties.getProperties()));
        super.doSend(mimeMessage, object);

        // 轮询
        currentMailId = (currentMailId + 1) % usernameList.size();
    }
    private Properties asProperties(Map<String, String> source) {
        Properties properties = new Properties();
        properties.putAll(source);
        return properties;
    }
    @Override
    public String getUsername() {
        return usernameList.get(currentMailId);
    }
}

4、实现发送功能

@Component
public class RoncooJavaMailComponent {
    private static final String template = "mail/roncoo.ftl";
    @Autowired
    private FreeMarkerConfigurer freeMarkerConfigurer;
    @Autowired
    private RoncooJavaMailSenderImpl javaMailSender;

    public void sendMail(String email) {
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("email", email);
        try {
            String text = getTextByTemplate(template, map);
            send(email, text);
        } catch (IOException | TemplateException e) {
            e.printStackTrace();
        } catch (MessagingException e) {
            e.printStackTrace();
        }
    }
    private String getTextByTemplate(String template, Map<String, Object> model) throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException, TemplateException {
        return FreeMarkerTemplateUtils.processTemplateIntoString(freeMarkerConfigurer.getConfiguration().getTemplate(template), model);
    }
    private String send(String email, String text) throws MessagingException, UnsupportedEncodingException {
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
        InternetAddress from = new InternetAddress();
        from.setAddress(javaMailSender.getUsername());
        from.setPersonal("龙果学院", "UTF-8");
        helper.setFrom(from);
        helper.setTo(email);
        helper.setSubject("测试邮件");
        helper.setText(text, true);
        javaMailSender.send(message);
        return text;
    }
}

flt代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <div style="width: 600px; text-align: left; margin: 0 auto;">
        <h1 style="color: #005da7;">龙果学院</h1>
        <div style="border-bottom: 5px solid #005da7; height: 2px; width: 100%;"></div>
        <div style="border: 1px solid #005da7; font-size: 16px; line-height: 50px; padding: 20px;">
            <div>${email},您好!</div>
            <div>
                这是个测试
            </div>
            
            <div style="border-bottom: 2px solid #005da7; height: 2px; width: 100%;"></div>
            <div>扫一扫,关注龙果学院微信公共号,里面更多精彩推荐</div>
            <div>
                <img src="http://account.roncoo.com/images/qrcode.png" alt="龙果学院公众号二维码" />
            </div>
            <div>
                想了解更多信息,请访问 <a href="http://www.roncoo.com">http://www.roncoo.com</a>
            </div>
        </div>
    </div>
</body>
</html>

html、js代码

<input type="text" name="email" id="email" />
<button id="send">发送邮件</button>

$(function(){
    $('#send').click(function(){
        var email = $('#email').val();
        $.ajax({
            url:'/api/mail',
            type:'post',
            data:{'email':email},
            success:function(msg){
                alert(msg);
            }
        });
    });
})

java代码

@Autowired
private RoncooJavaMailComponent component;
@RequestMapping(value = "mail")
    public String mail(String email) {
        component.sendMail(email);
        return "success";
    }

相关文章

网友评论

      本文标题:springboot

      本文链接:https://www.haomeiwen.com/subject/xhrcoqtx.html