个人技术总结

个人技术总结

目录

SpringBoot技术概述

SpringBoot是后端开发轻量级的框架之一,主要用于网页后端开发。而相比于Spring框架,SpringBoot通过“约定大于配置”的方法简化了应用搭建和开发过程,对于小白来说上手比较快。SpringBoot起源于Spring,对于刚接触的人来说,比较难理解的就是其IOC与AOP。

技术详述

一个软件通常都需要存储与检索数据,遵循业务逻辑与规则并对数据库进行事务管理、日志管理等。而Spring通过IOC与AOP两种方式去实现两种事务管理与日志管理功能。简要的来说,AOP(面向切面编程)就是将分布在各个函数中的事务管理与日志管理代码抽取出来,然后在代码编译或运行时织入相应的切面。而IOC(控制反转)是Spring管理其基本单位Bean的方式,对象的创建由程序通过依赖注入的方式实现,而不是由开发人员创建。

首先说明软件运行的环境,IntelliJ IDEA 2020.3.2、MySQL 8.0、SpringBoot 2.5.2

相较于Spring来说,SpringBoot极大幅度的简化了配置流程,开发人员需要配置的文件没有那么多了。其基本步骤大致如下:

  1. 在application.properties中配置数据源(使用的持久层框架不同,相应配置也不同)
  2. 创建相应的实体类与数据库表相对应
  3. 编写相应Dao层、Service层与Controller层代码处理请求。

下面以的用户表查询请求为例,使用持久层框架为JPA(假设用户表有主键id、account与password三个字段):

一、配置数据源代码:

server.port=8082
spring.datasource.url=jdbc:mysql://localhost:3306/tmall?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
spring.datasource.username =root
spring.datasource.password =123456

比较关键的是spring.datasource.url的属性,并且由于IDEA与MySQL版本问题很容易会出现两个问题。这个在后面的问题模块讲解。

二、实体类代码

我们需要编写相应实体类User与数据库中的User表相映射:

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;//主键ID
    private String account;//账号
    
    //返回json数据时,忽略密码字段
    @JsonIgnore
    private String password;//密码

}

其中@Entity是对实体的注释,需要配合@Id使用,否则会报错。

三、Dao层代码

然后我们可以编写用户类的Dao层接口,UserDao,例如根据账号查找一个用户:

@Repository
public interface UserDao extends JpaRepository<User,Integer> {

    /**
     * 根据账号查询用户
     * @param account
     * @return User
     */
    @Query(value = "SELECT * from user where user.account_num = ?1",nativeQuery = true)
    User findByAccount_num(String account);
}

@Repository注解说明这个类属于持久层。

使用JPA时,Dao层需要继承JpaRepository<User,Integer>,其中User代表实体类名,Integer代表了主键类型。当然,一般查询数据比较简单时,可以直接使用findBy***方法,通过分析方法名来实现查询。而查询数据比较复杂时使用@Query注解。这里仅为演示@Query用法。

四、业务层代码

然后我们就可以开始着手编辑Service层代码,实现相关的功能,例如查询一个用户:

@Service
public class UserService {
    @Autowired
    UserDao userDao;


    /**
     * 根据账号查询用户
     * @param account
     * @return
     */
    public User findUserByAccount(String account){
        return userDao.findByAccount_num(account);
    }
}

@Service注解说明这个类属于业务层代码。 在UserService使用@Autowired注解依赖注入UserDao对象实例,然后使用UserDao的相关方法。这就是Spring的IOC的实现方式之一。

五、控制层代码

之后,我们需要编写相关控制层代码来处理前端的请求,例如查找用户信息:

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    UserService userService;  
    
    /**
     * 查询用户信息
     * /findOneUser/{account}
     * @param account
     * @return
     */
    @RequestMapping(value = "/findOneUser/{account}", method = RequestMethod.GET)
    public JSONObject findUserInfo(@PathVariable(value = "account") String account){
        User user = userService.findUserByAccount(account);
        JSONObject jsonObject = new JSONObject();

        jsonObject.put("msg", "操作成功");
        jsonObject.put("code",Constant.SUCCESS);
        jsonObject.put("data", user);

        return jsonObject;
    }
}

在Spring中,控制层有两种注解,一种是@Controller,使用该注解时,视图解析器可以解析return 的jsp,html页面,并且跳转到相应页面;若返回json等内容到页面,则需要加@ResponseBody注解。而@RestController注解只返回json数据,不能返回jsp,html页面。同样的,也需要在UserController中使用@Autowired注入UserService实例。

方法上的注解 @RequestMapping用于映射URL,当其用于类定义处时,规定初步的请求映射,相对于web应用的根目录;而用于方法定义处时,进一步细分请求映射,相对于类定义处的URL,以上面代码为例,前端调用查询用户URL为/user/findOneUser/{account}。其中{account}为路径变量,我们使用这个变量去数据库里查询用户。当然,这里接受前端参数可以使用多种方式,例如使用JSONObject对象等等,就不多赘述。通过业务层代码获取相关用户数据后,使用JSONObject返回给前端即可。

其处理请求流程大致为:

1.用户通过浏览器向服务器发送请求,请求会被Spring MVC的前端控制器DispatcherServlet所拦截;

2.DispatcherServlet拦截到请求后,会调用HandlerMapping处理器映射器;

3.处理器映射器根据请求URL找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;

4.DispatcherServlet会通过返回信息选择合适的HandlerAdapter(处理器适配器)

5.HandlerAdapter会调用并执行Handler(处理器),这里的处理器指的就是程序中编写的Controller类,也被称之为后端控制器;

6.Controller执行完成后,会返回一个ModelAndView对象,该对象中会包含视图名或包含模型和视图名;

7.HandlerAdapter将ModelAndView对象返回给DispatcherServlet;

8/DispatcherServlet会根据ModelAndView对象选择一个合适的ViewReslover(视图解析器);

9.ViewReslover解析后,会向DispatcherServlet中返回具体的View(视图);

10.DispatcherServlet对View进行渲染(即将模型数据填充至视图中);

11.视图渲染结果会返回给客户端浏览器显示。

总结:

以上就是使用SpringBoot实现后端对数据库操作的大致流程,其项目代码大致分为三类entity实体类,service业务类与controller控制器类。当然,实际的项目中还会有其他的代码类,例如常量类、异常处理类等等,由于篇幅原因就不过多展开。

遇到问题

一、数据库连接问题

  1. 报错信息:com.mysql.cj.exceptions.InvalidConnectionAttributeException: The server time zone value is unrecognized……这种情况主要是由于时区问题,IDEA中配置数据库时默认使用的时区是UTC,所以要么修改IDEA的时区为Asia/Shanghai,要么在 JDBC 的连接 url 部分(spring.datasource.url)加上serverTimezone=UTC。

  2. 现在网上大部分教程使用的都是MySQL5.3的版本,其 JDBC 的连接 url 部分基本就是jdbc:mysql://localhost:3306/tmall就可(tmall代表数据库名)。但MySQL 5.5.45+、5.6.26+和5.7.6+以后的版本在进行连接时会默认需要SSL连接,不然会提示警告信息Establishing SSL connection without server's identity verification is not recommended,解决方法就是在JDBC 的连接 url 部分添加useSSL=false

  3. 驼峰命名导致实体类部分字段值为null。这个是由于JPA默认的命名方式导致的问题。JPA默认使用的的是ImprovedNamingStrategy策略,即JPA对数据表默认的命名规则为两个单词之间以下划线分割。虽然实体字段和数据库字段一致,但是 JPA 的生成的sql语句还是把小驼峰转化为 下划线了所以查不到。比如实体类中有属性字段createTime,数据表中字段也为createTime,但由于命名策略问题,实体类中createTime 会被 JPA 创建为字段 create_time,导致找不到相关字段,于是其值为null。解决方法就是将命名策略修改为PhysicalNamingStrategyStandardImpl。即在application.properties中添加spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

二、第三方依赖jar包的问题

1. 打包问题

SpringBoot都是使用Maven来管理相应依赖文件,并且使用Maven来进行打包。但需要导入第三方的依赖包时,Maven默认不会将第三方依赖包打包进相应的jar文件的。解决方法如下:

首先我们应该在Maven中添加第三方依赖,在src中添加lib文件夹存放第三方jar包,pom.xml代码如下

<dependency>
   <groupId>域名</groupId>
   <artifactId>项目名</artifactId>
   <version>版本号</version>
   <scope>system</scope>
   <systemPath>${basedir}/src/lib/文件名字.jar</systemPath>
  </dependency>

其中{basedir}是自带变量,指的是当前项目的绝对路径。

然后我们需要在pom.xml中添加一条属性:

<build>
	<configuration>
		<includeSystemScope>true</includeSystemScope>
	</configuration>
</build>

true代表maven打包时会将外部引入的jar包(比如在根目录下或resource文件下新加外部jar包)打包到项目jar,这样就解决了第三方jar包问题。

2.签名错误

β冲刺时,我们给App添加了每日定时向用户推送菜谱的功能,使用的就是友盟的第三方jar包。但很奇怪的是,在进行测试时,发现在idea中运行时是成功的,用户在手机上可以获取消息,但使用命令行运行相应jar包时就会出现签名错误的问题,导致消息推送不了。这实在是让人非常困惑。最终解决方式还是查看了签名错误的相关实例,其中有一个引起了我的注意,就是这个jar包需要在utf-8 zh_cn的编码下才能正常运行,而通常服务器和windowcmd的编码不是,所以在计算签名时才会出错。解决方法就是在运行jar包时,添加-Dfile.encoding=utf-8命令。

总结

通过这次实践,我对SpringBoot有了进一步的了解,而项目中遇到的种种问题我在网络资料与同学帮助下也一一克服,收获还是非常大的。一开始遇到这些不熟悉的问题还是非常棘手的,就不如驼峰命名导致的null问题,一开始完全没有想到会是JPA默认命名策略的问题。最终还是在组内同学的帮助下才解决问题。

参考博客

  1. [更新 Spring Data JPA 之数据表名的命名规则为驼峰命名法 - 雨尘365 - 博客园 (cnblogs.com)](更新 Spring Data JPA 之数据表名的命名规则为驼峰命名法 - 雨尘365 - 博客园 (cnblogs.com))

  2. [SSL警告]((14条消息) 运行项目连接Mysql时出现警告Establishing SSL connection without server's identity verification is not recommende_棒叔叔的博客-CSDN博客)

  3. [详解springboot解决第三方依赖jar包的问题](详解springboot解决第三方依赖jar包的问题_java_脚本之家 (jb51.net))

  4. [Springboot中如何引入本地jar包,并通过maven把项目成功打包成jar包部署]((14条消息) Springboot中如何引入本地jar包,并通过maven把项目成功打包成jar包部署_艾特老司机-CSDN博客_includesystemscope)

  5. nodejs调用友盟push api: 签名错误问题

posted @ 2021-06-26 15:06  Phara  阅读(129)  评论(0编辑  收藏  举报