美文网首页IT全栈圈
全栈之路-Springboot初试

全栈之路-Springboot初试

作者: 渝聆墨 | 来源:发表于2018-12-16 13:23 被阅读35次

    前言

    距离2018年结束还有15天,也是我正式步入开发行业的第三个年头,他们都说步入开始后悔,但是仔细想想其实这三年来还是挺好的,有枯燥乏味,有焦躁不安,有自暴自弃,还有在第二天早晨重新焕发坐上清晨的公交车奔向公司。
    三年来的时光,先后换了4家公司,第一家公司呆了近2年,而后的更换公司却有些频繁,从重庆再到杭州,虽然我很不想这样,但是这个行业好像就那么如此。
    第一年的工作是Android开发,让我对Android有了深入的了解,包括一些硬件基础摄像头,蓝牙,USB接口,还有音频合成等,也打下了不错的java基础。
    第二年的工作主要倾向于web前端开发,公司业务逐步拓展,作为一线开发者的我开始学习前端,从html,css,js,再到jquery,vue,微信小程序,也为我打开了前端开发的知识大门。
    第三年的工作是有些偏向于管理方向,开始带领公司小团队,同时也更换两家公司,这一年开始学习了javaweb的学习,从年初到年末,先后利用工作之余,学习了Servlet、Jsp、struts2,spring等,最后开始对spring全家桶着迷。
    这一路走来,第一家公司跟着公司大佬学习,学会了对代码严谨,还有测试,如今始终还记老板时常对我的念叨(老板是技术出身的):敲代码是一件很神圣的事情,所以要对代码充满敬畏之心,所以修改代码必须细心再细心,提交代码要反复测试。那段时间让我知道了对测试的重要性,还有代码的严谨。我真的很感谢老板,收留了毕业后走投无路的我,也教会了很多知识。第二家公司,担任了公司项目经理,负责公司项目体系策划,开发团队管理,从需求分析到最后项目上线,也让我有了一把应聘别人的经验。所以我觉得开发并不是那么无聊,关键看做开发的人,大概我也是假的开发,不过经常被人吐槽万金油确实不好受。

    开始

    理论知识

    javaweb后端开发,对于正式接触这个技术栈的时候,第一印象就是数据,每天所做就是与数据打交道,从简单上考虑,所有的后端开发无论java,php,pythan,还是其他的语言无非就是四种姿势:


    • 但是说起来就四个字,但是只要真正接触了后端开发后才发现,这四个字不简单。

    增,我们要考虑几种业务模块场景:
    1.直接增加一条数据(新增用户)
    2.查询后增加指定字段(主要为更新字段)
    3.新增表(数据新增表,与现有表相关联,列如:用户表,关联表就有用户登录信息表,会员表,权限表等)
    4.新增字段(业务需求新增字段,不过最好前期架构好字段)
    ......
    增加数据这业务模块,对于菜鸟而言估计就是要啥数据,就不断新增,于是就导致数据库臃肿,业务链繁琐,于是查询数据缓慢,最后后台服务器不堪重负崩了。

    删,删除的业务场景同样比繁琐。
    1.删除单条信息(常见为注销用户,一般产品这些不会作为直接删除业务)
    2.删除多条信息(遍历删除,或则条件删除,常见为注销用户,删除他的所有关联信息)
    ......删除业务又同时依赖于查询业务模块

    修改,也是更新,业务逻辑也是在后端业务中比较繁琐的一个部分
    1.字段修改(例如更新用户登录状态,商品状态,订单状态)
    2.多条记录修改(一般为分类常见,多数为一对多表,多对多表场景)
    3.多表修改(查询多表修改,耗时很长,应该避免出现超过3个表同时修改场景,减少服务器负担)
    .....

    查询,是后端数据的重中之中,因为前端数据展示,才有后端数据的可用之处,查询的模块就相对比较多
    1.单条记录查询(查询某个业务场景)
    2.多条记录查询(查询列表,常见为商品列表,用户列表等)
    3.按照某个字段排序查询(升序,降序)
    4.分页查询
    ......
    以上就是后端大概业务场景的分析
    springboot代码是采用注解方式开发一般分为三部分:@Entity数据库类,JpaRepository接口类,@RestController业务实体类。

    • JpaRepository是用于整合业务查询模块。
      接下我们根据具体的场景来实现具体的springboot代码。

    代码实践

    springboot提供整套的封装方法,大量地减少了许多业务场景,接下来我们看看springboot为我们封装的常用方法,CrudRepository源码如下:

    import java.util.Optional;
    @NoRepositoryBean
    public interface CrudRepository<T, ID> extends Repository<T, ID> {
        //保存对象
        <S extends T> S save(S var1);
         //根据迭代器来保存
        <S extends T> Iterable<S> saveAll(Iterable<S> var1);
        //根据id来查询值
        Optional<T> findById(ID var1);
        //id是否存在
        boolean existsById(ID var1);
        //使用配置的TypeRepresentationStrategy来加载所有实体,可能会返回一个大的结果
        Iterable<T> findAll();
        //根据迭代器查找
        Iterable<T> findAllById(Iterable<ID> var1);
        // 使用配置的TypeRepresentationStrategy,根据策略,此数字可能是近似值
        long count();
        //根据迭代器查找id来删除给定的实体
        void deleteById(ID var1);
        //通过调用其entity.remove()方法删除给定实体
        void delete(T entity);
         //根据迭代器删除对象集合
        void deleteAll(Iterable<? extends T> var1);
        //删除此类型的所有实体,请小心使用
        void deleteAll();
    }
    
    • 其中PagingAndSortingRepository 继承于CrudRepository
    @NoRepositoryBean
    public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
        List<T> findAll(); //查询全部
    
        List<T> findAll(Sort var1);//排序查询
    
        List<T> findAllById(Iterable<ID> var1);//根据id查询
    
        <S extends T> List<S> saveAll(Iterable<S> var1);
        //刷新对数据库的所有挂起更改。
        void flush();
        //保存实体并立即刷新更改。
        <S extends T> S saveAndFlush(S var1);
        //删除批处理中的给定实体,这意味着它将创建单个实体[`Query`]
        void deleteInBatch(Iterable<T> var1);
        //删除批量调用中的所有实体。
        void deleteAllInBatch();
        //返回对具有给定标识符的实体的引用。
        T getOne(ID var1);
        
        <S extends T> List<S> findAll(Example<S> var1);
    
        <S extends T> List<S> findAll(Example<S> var1, Sort var2);
    }
    

    以上就是springboot给我们提供的封装常用方法的源码,下面我们来实战运用。

    新增&更新

    • 在springboot中新增和更新都可以调用CrudRepository 中的save方法来保存数据。
      需求:注册用户
      场景:注册用户需要用户输入简单的手机号码,密码进行注册登录。并且生成用户特定uid字段。
    数据类:
    @Entity
    public class User {
        //表id
        @Id
        @GeneratedValue
        private Integer id;
        //用户id
        private String uid;
        //用户昵称
        private String user_name;
        //用户电话
        private String user_phone
        //用户密码
        private String user_pwd;
        //get&set省略.....
    }
    
    

    JpaRepository接口类:

    @Repository
    public interface UserRepository  extends JpaRepository<User,Integer> {}
    
    业务类:
    @RestController
    @RequestMapping("/api")
    @CrossOrigin
    public class UserController {
        @Autowired
        private UserRepository userRepository;
    
        /**
         * 注册用户
         * @param user
         * @return
         */
        @PostMapping(value = "/register")
        public RespEntity addUser(User user) {
            if (user != null) {
                List<User> users = userRepository.queryUser(user.getUserPhone());
                if (users == null) {
                    //判断手机号是否正确
                    if (!StringUtil.isExistLong(user.getUserPhone())) {
                        return new RespEntity(RespCode.WARN, "请输入手机号码");
                    }
                    //判断密码是否输入正确
                    if (!StringUtil.isExist(user.getUserPwd(), 8)) {
                        return new RespEntity(RespCode.WARN, "请输入正确的密码");
                    }
                    //获取添加时间
                    Long addtime = DateUtil.getTime();
                    //将时间与手机号生成MD5编码
                    String uid = MD5.md5(String.valueOf(addtime), user.getUserPhoto());
                    if (uid!= null&&uid.length()>0) {
                        user.setUid(uid);
                        //保存数据
                        userRepository.save(user);
                        return new RespEntity(RespCode.SUCCESS, user);
                    }else {
                        return new RespEntity(RespCode.WARN,"生成用户身份ID失败,请重试");
                    }
                } else {
                    return new RespEntity(RespCode.WARN, "用户已存在");
                }
            } else {
                return new RespEntity(RespCode.WARN);
            }
        }
    }
    

    以上就实现了注册用户,特别地简单。

    • RespEntity是返回封装。
    • StringUtil是判断数据字符是否为空工具类。
    • queryUser 方法是使用在JpaRepository中的 @Query条件查询实现的,后面会说明。
    /**
         * 更新用户
         *
         * @param user
         * @return
         */
        @PostMapping(value = "/updatauser")
        public RespEntity updataUser(User user) {
            //查询是否有这个用户
            User oldUser = userRepository.findAll().get(user.getId());
            if (oldUser != null) {
               //如果用户存在就更新
                userRepository.save(user);
                return new RespEntity(RespCode.SUCCESS);
            } else {
                return new RespEntity(RespCode.WARN);
            }
        }
    

    更新功能就这么简单,当然这还不够完善。

    注意事项:
    • 建立每个表格都要增加时间字段,比如新增时间,更新时间,如果需要做接口访问统计的最好还要新增一个访问接口统计字段。
    • 访问数据的时候为了数据安全,都要对其进行身份验证。

    删除

    需求:删除(注销)用户
    场景:根据用户手机号删除用户

    • 这里就需要用到JpaRepository功能,需要给他扩展接口方法,我现在需要一个根据用户手机号查询到该条数据的方法,如下:
     @Query(value = "select * from user as u where u.user_phone=?",nativeQuery = true)
        List<User> queryUser(Long userPhone);
    

    然后再在Controller中调用查询到该用户:

       @PostMapping(value = "/deluser")
        public RespEntity delUser(@RequestParam("userPhone") Long userPhone) {
            //查询是否有该手机用户
            List<User> users=userRepository.queryUser(Long.valueOf(userPhone));
            if (users!=null&&users.size()>0){
                //获取该用户
                User user= users.get(0);
                if (user!=null){
                    //调用删除
                    userRepository.delete(user);
                    return new RespEntity(RespCode.SUCCESS,"删除成功");
                }else{
                    return new RespEntity(RespCode.WARN,"用户不存在");
                }
    
            }else {
                return new RespEntity(RespCode.WARN,"用户不存在,请重新输入");
            }
    
        }
    

    查询

    上面的增删改中,其实也提到几种查询方法:

    • 查询整个数据表findAll
    repository.findAll();
    
    • 用户 @Query条件查询
    @Query(value = "select * from user as u where u.user_phone=?",nativeQuery = true)
        List<User> queryUser(Long userPhone);
    

    然后比较常用的还有排序查询,eg:
    需求:根据年龄大小排序查询用户

    • 首先我们需要在数据表类里新增一个年龄字段:
      @Column(name="user_sex")
        private Integer userSex;
    
    • @Column(name="user_sex") 代表把该字段作为排序字段,值为user_sex。
        /**
         * 查询文章列表#热度查询-阅读量
         */
        @GetMapping(value = "/like_usersex_list")
        public RespEntity findListSortSingleCondition() {
            Sort sort = new Sort(Sort.Direction.ASC, "user_sex");
            List<User> userlist= userRepository.findAll(sort);
            if (userlist!= null && userlist.size() > 0) {
                return new RespEntity(RespCode.SUCCESS, userlist);
            } else {
                return new RespEntity(RespCode.WARN);
            }
        }
    
    • Sort 对象为排序条件对象,需要提交排序条件+排序按照升序还是降序。
      1.Sort.Direction.ASC 升序排列
      2.Sort.Direction.DESC 降序排列
    • 多条件查询
      /**
         * 多条件排序
         */
        public List<User> findListSortMultiCondition() {
            List<Sort.Order> orders = new ArrayList<Sort.Order>();
            Sort.Order orderId = new Sort.Order(Sort.Direction.DESC, "id");
            Sort.Order orderAge = new Sort.Order(Sort.Direction.DESC, "user_sex");
            orders.add(orderId);s
            orders.add(orderAge);
            Sort sort = new Sort(orders);
            return userRepository.findAll(sort);
        }
    
    • 除此之外还有分页查询,springboot也提供了详细的分页查询api,就是利用Pageable ,如下:
    @Query(value = "select u from  article u where u.name like  %?1% ")
        Page<Article> findUserLikeByPage(String name, Pageable page);
    

    总结

    springboot还有很多乐趣,作为初学javaweb的人有很大便捷,至少对于我而言,不再是想以前那么提起后台开发就觉得是一件很高深莫测的东西,有些东西没有去接触尝试,就不要对其产生畏惧,那是自己杀死了自己。
    三年前我有了小梦想就是成为全栈工程师,当初有人说,你能够把一项搞懂就行了,但是三年的今天,我已经跨出了那么一小步,虽然这一步很小,未来还很远,但是我还是想沿着这条路走下去,看看这条路未来的路是怎么样子的,万金油也好,我只是想活着自己想要活着的样子罢了。
    既然想了,就去做吧,干嘛想那么多有的没的。

    相关文章

      网友评论

        本文标题:全栈之路-Springboot初试

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