1. 选择spring intializer
  2. 填写maven坐标GAV
  3. 选择依赖(spring-web\lombok)
  4. 完成
    1. 访问start.spring.io,根据所选依赖,生成代码
    2. 返回一个项目zip
    3. 解压,导入到idea
    4. maven编译

image.png
Application类,一定放在根目录,跟其他包同级

打包是jar包,jar包怎么部署?

Spring Boot使创建独立的、生产级的、基于Spring的应用程序变得容易,您可以 “just run” 这些应用程序。
我们对于spring平台和第三方库做了统一的视图,以便于以最小的代价开始开发。大多数Spring Boot应用程序需要最少的Spring配置。

特征

  • 创建独立的Spring应用程序:不依赖于其他的工具或者平台,直接运行
  • 直接内嵌入Tomcat、Jetty或Undertow (无需部署WAR文件): 直接启动tomcat运行,无须部署war包
  • 提供自包含的 “starter” 依赖,以简化您的构建配置
    • 将需要的依赖进行了依赖传递,简化依赖
    • 在spring-boot中使用的依赖都是starter依赖,换言之,引入springmvc,不直接导入spring-webmvc而是使用spring-boot-starter-web
    • 命名规范:官方spring-boot-starter-xxx 民间:xxx-spring-boot-starter
    • 简化配置
  • 尽可能自动配置Spring和第三方库
    • 集成springmvc,自动配置viewresolver
  • 提供可用于生产级功能,如指标、运行状况检查和外部化配置
  • 绝对没有代码生成,也不需要XML配置

集成mybatis

  1. 加依赖(mybatis-starter、mysql) ```xml org.mybatis.spring.boot mybatis-spring-boot-starter 2.2.0
mysql mysql-connector-java 5.1.47 2. 配置(yml) application.yml 用缩进表达层次yaml server: port: 8000 spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/boss52 username: root password: root mybatis: type-aliases-package: com.example.demo56.entity configuration: map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl mapper-locations: classpath:mappers/**/.xml 3. @MapperScanjava @MapperScan(“com.example.demo56.mapper”) //mapper扫描 @EnableTransactionManagement //开启事务 public class Demo56Application { 4. 验证 mapperjava public interface OpLogMapper { @Select(“select oplogid,op_name from boss_oplog”) public List> findAll(); } 外化配置配置文件,命名约定 : application / boostarp 后缀: yml/yaml/properties <a name="jLbAd"></a> ## Spring-Boot实现原理 POM.xml - 依赖版本的管理 BOM spring-boot-starter-parent --> Spring-boot-dependencies(所有的依赖版本) - 统一版本,减少技术成本 - 解决jar包之间版本兼容的问题,尽量不写版本,沿用父项目中的版本 - starter依赖 - 简化依赖 - 自动配置 - spring-boot-maven-plugin插件 - 通过maven运行spring-boot项目 mvn spring-boot:run - 打包 jar (fatjar,支持直接运行) - mvn clean package -Dmaven.test.skip=true - java -jar demo56-0.0.1-SNAPSHOT.jar <a name="oKLv3"></a> ## 自动配置原理 - 目的: 集成第三方框架之后,可自动配置,集成到spring中 ![image.png](https://cdn.nlark.com/yuque/0/2021/png/953441/1623742959469-05cb1f25-444f-4ce0-bb67-4316e4a3bdec.png#height=576&id=KFycL&margin=%5Bobject%20Object%5D&name=image.png&originHeight=576&originWidth=1248&originalType=binary&ratio=1&size=42546&status=done&style=none&width=1248)<br />问题:<br />mybatis集成到spring中的方式是一样的,换言之,以下代码在不同项目中是重复存在的java //sqlSessionFactoryBean配置,替代mybatis-config.xml @Bean public SqlSessionFactoryBean sqlSessionFactoryBean() throws IOException { SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); //数据源 sqlSessionFactoryBean.setDataSource(dataSource()); //别名包 sqlSessionFactoryBean.setTypeAliasesPackage(“com.woniuxy.framework.model”); org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(); //下划线映射到驼峰 configuration.setMapUnderscoreToCamelCase(true); //日志 configuration.setLogImpl(StdOutImpl.class); sqlSessionFactoryBean.setConfiguration(configuration); //配置文件位置 PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver(); Resource[] resources = patternResolver.getResources(“classpath:mappers/**/.xml”); sqlSessionFactoryBean.setMapperLocations(resources); return sqlSessionFactoryBean; } 1) 重复的,套路式的配置代码,在不同项目中是一样的<br />2) 部分配置,需要手动配置,每个项目是不同<br />如果有一种方式,能够将重复的配置代码封装掉,并且提供了修改的配置项的配置的方式,能够很大的提高效率<br />spring-boot的starter完成以上功能 技术实现: 1. @SpringBootApplication 包含了@EnableAutoConfiguration,启动自动配置 1. xxx-spring-boot-starter 的包下有一个文件夹 META-INF,文件叫spring.factories,包含了自动配置类路径 # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration,\ org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
3. 定位自动配置类,自动配置类提供了必要的bean 的配置java @org.springframework.context.annotation.Configuration //配置类 public class MybatisAutoConfiguration implements InitializingBean { @Bean //注册springbean @ConditionalOnMissingBean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean factory = new SqlSessionFactoryBean(); factory.setDataSource(dataSource); … //设置配置map-underscore-to-camel-case、log-impl applyConfiguration(factory); if (this.properties.getConfigurationProperties() != null) { factory.setConfigurationProperties(this.properties.getConfigurationProperties()); } if (!ObjectUtils.isEmpty(this.interceptors)) { factory.setPlugins(this.interceptors); } … //设置别名包 if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) { factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage()); } … //mapper.xml的路径位置 if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) { factory.setMapperLocations(this.properties.resolveMapperLocations()); } …. return factory.getObject(); } } ``` 4. 需要自定义的配置,自动配置类MybatisAutoConfiguration关联了一个配置属性类 @EnableConfigurationProperties
(MybatisProperties.class)_ java @org.springframework.context.annotation.Configuration @ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class }) @ConditionalOnSingleCandidate(DataSource.class) >>>>@EnableConfigurationProperties(MybatisProperties.class) @AutoConfigureAfter({ DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class }) public class MybatisAutoConfiguration implements InitializingBean { private static final Logger logger = LoggerFactory.getLogger(MybatisAutoConfiguration.class); >>>> private final MybatisProperties properties; 5. 配置属性类与applicatoin.yml配置文件里的属性相对应 java //标记为配置属性类,指定前缀,此处为mybatis,完整配置项名为mybatis.属性名 例如mybatis.typeAliasesPackage @ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX) public class MybatisProperties { public static final String MYBATIS_PREFIX = "mybatis"; ... private String typeAliasesPackage; image.png
1) 重复的,套路式的配置代码,在不同项目中是一样的 —-> 自动配置类
2) 部分配置,需要手动配置,每个项目是不同 —-> 配置属性类+外化配置文件 ## 手写starter 1. 创建quickstart项目,编写kuaidiniao项目 1. mvn clean install 2. 创建quickstart项目,编写kuaidiniao-spring-boot-starter 1. 添加依赖 kuaidiniao / spring-boot-starter ```xml <?xml version=”1.0” encoding=”UTF-8”?> 4.0.0 com.woniuxy.tool kuaidiniao-spring-boot-starter 1.0-SNAPSHOT kuaidiniao-spring-boot-starter http://www.example.com UTF-8 1.8 1.8 2.5.1 junit junit 4.11 test com.woniuxy.tool kuaidiniao 1.0-SNAPSHOT
  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter</artifactId>
  4. <version>${spring-boot.version}</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot</artifactId>
  9. <version>${spring-boot.version}</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.springframework.boot</groupId>
  13. <artifactId>spring-boot-autoconfigure</artifactId>
  14. <version>${spring-boot.version}</version>
  15. </dependency>
  16. <dependency>
  17. <groupId>org.springframework.boot</groupId>
  18. <artifactId>spring-boot-configuration-processor</artifactId>
  19. <version>${spring-boot.version}</version>
  20. <optional>true</optional>
  21. </dependency>

  1. b. 编写resources/META-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.woniuxy.tool.KuaiDiNiaoAutoConfiguration

  1. c. 编写自动配置类和配置属性类
  2. ```java
  3. package com.woniuxy.tool;
  4. import org.springframework.boot.context.properties.ConfigurationProperties;
  5. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  6. import org.springframework.context.annotation.Bean;
  7. import org.springframework.context.annotation.Configuration;
  8. @Configuration
  9. @EnableConfigurationProperties(KuaiDiNiaoProperties.class)
  10. public class KuaiDiNiaoAutoConfiguration {
  11. private final KuaiDiNiaoProperties properties;
  12. public KuaiDiNiaoAutoConfiguration(KuaiDiNiaoProperties properties) {
  13. this.properties = properties;
  14. }
  15. @Bean
  16. public KuaiDiNiaoQueryAPI kuaiDiNiaoQueryAPI(){
  17. KuaiDiNiaoConfig config =new KuaiDiNiaoConfig();
  18. config.setUserKey(this.properties.getUserKey());
  19. config.setUserSecret(this.properties.getUserSecret());
  20. config.setReqURL(this.properties.getReqURL());
  21. return new KuaiDiNiaoQueryAPI(config);
  22. }
  23. }
  24. ----
  25. package com.woniuxy.tool;
  26. import org.springframework.boot.context.properties.ConfigurationProperties;
  27. @ConfigurationProperties(prefix = "kuaidiniao")
  28. public class KuaiDiNiaoProperties {
  29. private String userKey;
  30. private String userSecret;
  31. private String reqURL;
  32. public String getUserKey() {
  33. return userKey;
  34. }
  35. public void setUserKey(String userKey) {
  36. this.userKey = userKey;
  37. }
  38. public String getUserSecret() {
  39. return userSecret;
  40. }
  41. public void setUserSecret(String userSecret) {
  42. this.userSecret = userSecret;
  43. }
  44. public String getReqURL() {
  45. return reqURL;
  46. }
  47. public void setReqURL(String reqURL) {
  48. this.reqURL = reqURL;
  49. }
  50. }

d. mvn clean install

  1. 在demo56使用kuaidiniao-spring-boot-starter

    1. 引入kuaidiniao的starter依赖
    2. 配置application.yml

      1. kuaidiniao:
      2. user-key: 1663793
      3. user-secret: 0d253737-fc22-4064-87cd-5052fc6af857
      4. req-u-r-l: http://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx

      c. 引入并直接使用

      1. @Autowired
      2. private KuaiDiNiaoQueryAPI kuaiDiNiaoQueryAPI;
      3. @GetMapping("query")
      4. public String query(String expCode,String expNo) throws Exception {
      5. return kuaiDiNiaoQueryAPI.getOrderTracesByJson(expCode,expNo);
      6. }

      image.png ```java package com.woniuxy.tool;

import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.security.MessageDigest; import java.util.HashMap; import java.util.Map;

/*

  • 快递鸟物流轨迹即时查询接口 *
  • @技术QQ群: 456320272
  • @see: http://www.kdniao.com/YundanChaxunAPI.aspx
  • @copyright: 深圳市快金数据技术服务有限公司 *
  • DEMO中的电商ID与私钥仅限测试使用,正式环境请单独注册账号
  • 单日超过500单查询量,建议接入我方物流轨迹订阅推送接口 *
  • ID和Key请到官网申请:http://www.kdniao.com/ServiceApply.aspx */ public class KuaiDiNiaoQueryAPI {
  1. //电商ID,我的账户名
  2. private String EBusinessID;
  3. //电商加密私钥,我的私钥,快递鸟提供,注意保管,不要泄漏
  4. private String AppKey;
  5. //请求url
  6. private String ReqURL;
  7. public KuaiDiNiaoQueryAPI(KuaiDiNiaoConfig config){
  8. this.EBusinessID=config.getUserKey();
  9. this.AppKey=config.getUserSecret();
  10. this.ReqURL=config.getReqURL();
  11. }
  12. /**
  13. * Json方式 查询订单物流轨迹
  14. * @throws Exception
  15. */
  16. public String getOrderTracesByJson(String expCode, String expNo) throws Exception{
  17. String requestData= "{'OrderCode':'','ShipperCode':'" + expCode + "','LogisticCode':'" + expNo + "'}";
  18. Map<String, String> params = new HashMap<String, String>();
  19. params.put("RequestData", urlEncoder(requestData, "UTF-8"));
  20. params.put("EBusinessID", EBusinessID);
  21. params.put("RequestType", "1002");
  22. String dataSign=encrypt(requestData, AppKey, "UTF-8");
  23. params.put("DataSign", urlEncoder(dataSign, "UTF-8"));
  24. params.put("DataType", "2");
  25. String result=sendPost(ReqURL, params);
  26. //根据公司业务处理返回的信息......
  27. return result;
  28. }
  29. /**
  30. * MD5加密
  31. * @param str 内容
  32. * @param charset 编码方式
  33. * @throws Exception
  34. */
  35. @SuppressWarnings("unused")
  36. private String MD5(String str, String charset) throws Exception {
  37. MessageDigest md = MessageDigest.getInstance("MD5");
  38. md.update(str.getBytes(charset));
  39. byte[] result = md.digest();
  40. StringBuffer sb = new StringBuffer(32);
  41. for (int i = 0; i < result.length; i++) {
  42. int val = result[i] & 0xff;
  43. if (val <= 0xf) {
  44. sb.append("0");
  45. }
  46. sb.append(Integer.toHexString(val));
  47. }
  48. return sb.toString().toLowerCase();
  49. }
  50. /**
  51. * base64编码
  52. * @param str 内容
  53. * @param charset 编码方式
  54. * @throws UnsupportedEncodingException
  55. */
  56. private String base64(String str, String charset) throws UnsupportedEncodingException {
  57. String encoded = base64Encode(str.getBytes(charset));
  58. return encoded;
  59. }
  60. @SuppressWarnings("unused")
  61. private String urlEncoder(String str, String charset) throws UnsupportedEncodingException{
  62. String result = URLEncoder.encode(str, charset);
  63. return result;
  64. }
  65. /**
  66. * 电商Sign签名生成
  67. * @param content 内容
  68. * @param keyValue Appkey
  69. * @param charset 编码方式
  70. * @throws UnsupportedEncodingException ,Exception
  71. * @return DataSign签名
  72. */
  73. @SuppressWarnings("unused")
  74. private String encrypt (String content, String keyValue, String charset) throws UnsupportedEncodingException, Exception
  75. {
  76. if (keyValue != null)
  77. {
  78. return base64(MD5(content + keyValue, charset), charset);
  79. }
  80. return base64(MD5(content, charset), charset);
  81. }
  82. /**
  83. * 向指定 URL 发送POST方法的请求
  84. * @param url 发送请求的 URL
  85. * @param params 请求的参数集合
  86. * @return 远程资源的响应结果
  87. */
  88. @SuppressWarnings("unused")
  89. private String sendPost(String url, Map<String, String> params) {
  90. OutputStreamWriter out = null;
  91. BufferedReader in = null;
  92. StringBuilder result = new StringBuilder();
  93. try {
  94. URL realUrl = new URL(url);
  95. HttpURLConnection conn =(HttpURLConnection) realUrl.openConnection();
  96. // 发送POST请求必须设置如下两行
  97. conn.setDoOutput(true);
  98. conn.setDoInput(true);
  99. // POST方法
  100. conn.setRequestMethod("POST");
  101. // 设置通用的请求属性
  102. conn.setRequestProperty("accept", "*/*");
  103. conn.setRequestProperty("connection", "Keep-Alive");
  104. conn.setRequestProperty("user-agent",
  105. "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
  106. conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
  107. conn.connect();
  108. // 获取URLConnection对象对应的输出流
  109. out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
  110. // 发送请求参数
  111. if (params != null) {
  112. StringBuilder param = new StringBuilder();
  113. for (Map.Entry<String, String> entry : params.entrySet()) {
  114. if(param.length()>0){
  115. param.append("&");
  116. }
  117. param.append(entry.getKey());
  118. param.append("=");
  119. param.append(entry.getValue());
  120. //System.out.println(entry.getKey()+":"+entry.getValue());
  121. }
  122. //System.out.println("param:"+param.toString());
  123. out.write(param.toString());
  124. }
  125. // flush输出流的缓冲
  126. out.flush();
  127. // 定义BufferedReader输入流来读取URL的响应
  128. in = new BufferedReader(
  129. new InputStreamReader(conn.getInputStream(), "UTF-8"));
  130. String line;
  131. while ((line = in.readLine()) != null) {
  132. result.append(line);
  133. }
  134. } catch (Exception e) {
  135. e.printStackTrace();
  136. }
  137. //使用finally块来关闭输出流、输入流
  138. finally{
  139. try{
  140. if(out!=null){
  141. out.close();
  142. }
  143. if(in!=null){
  144. in.close();
  145. }
  146. }
  147. catch(IOException ex){
  148. ex.printStackTrace();
  149. }
  150. }
  151. return result.toString();
  152. }
  153. private static char[] base64EncodeChars = new char[] {
  154. 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
  155. 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
  156. 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
  157. 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
  158. 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
  159. 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
  160. 'w', 'x', 'y', 'z', '0', '1', '2', '3',
  161. '4', '5', '6', '7', '8', '9', '+', '/' };
  162. public static String base64Encode(byte[] data) {
  163. StringBuffer sb = new StringBuffer();
  164. int len = data.length;
  165. int i = 0;
  166. int b1, b2, b3;
  167. while (i < len) {
  168. b1 = data[i++] & 0xff;
  169. if (i == len)
  170. {
  171. sb.append(base64EncodeChars[b1 >>> 2]);
  172. sb.append(base64EncodeChars[(b1 & 0x3) << 4]);
  173. sb.append("==");
  174. break;
  175. }
  176. b2 = data[i++] & 0xff;
  177. if (i == len)
  178. {
  179. sb.append(base64EncodeChars[b1 >>> 2]);
  180. sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
  181. sb.append(base64EncodeChars[(b2 & 0x0f) << 2]);
  182. sb.append("=");
  183. break;
  184. }
  185. b3 = data[i++] & 0xff;
  186. sb.append(base64EncodeChars[b1 >>> 2]);
  187. sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
  188. sb.append(base64EncodeChars[((b2 & 0x0f) << 2) | ((b3 & 0xc0) >>> 6)]);
  189. sb.append(base64EncodeChars[b3 & 0x3f]);
  190. }
  191. return sb.toString();
  192. }

}

  1. ```java
  2. package com.woniuxy.tool;
  3. public class KuaiDiNiaoConfig {
  4. private String userKey;
  5. private String userSecret;
  6. private String reqURL;
  7. public String getUserKey() {
  8. return userKey;
  9. }
  10. public void setUserKey(String userKey) {
  11. this.userKey = userKey;
  12. }
  13. public String getUserSecret() {
  14. return userSecret;
  15. }
  16. public void setUserSecret(String userSecret) {
  17. this.userSecret = userSecret;
  18. }
  19. public String getReqURL() {
  20. return reqURL;
  21. }
  22. public void setReqURL(String reqURL) {
  23. this.reqURL = reqURL;
  24. }
  25. }

作业

  1. 学生管理(增删改查)
    1. 学生姓名 学号 性别 年龄 专业 入学时间 咨询老师 班级
    2. 学生注册 / 学生毕业 / 学生分页查询
  2. 完成kuaidiniao案例

@SpringBootApplication

spring-boot的一些约定