微信小程序登录与图片上传

这个作业属于哪个课程2302软件工程
这个作业要求在哪里软件工程实践总结&个人技术博客
这个作业的目标软件工程实践总结
其他参考文献《构建之法》

一、技术概述

目前微信小程序登录通过前端的wx.login方法进行登录,初次登录需要上传头像与昵称。后端需要将前端上传的图片重命名并保存到服务器的文件夹中,并暴露图片访问方式,供前端访问图片。

二、技术详述

  • 1.前端上传头像图片,即将前端生成的临时图片URL地址传递给后端,后端根据文件上传接口接受文件,并编写文件保存方法保存图片。(代码中filePath多余,直接返回fileName,此时前端只收到了fileName,还不是一个可访问的图片;后续在前端调用login方法时,给后端传递数据,将fileName带给后端,后端处理成一个完整的URL返回给前端。)
//uploadPath存的是形如"D:\\pictures"这样的路径,当然在部署时需要改成服务器的文件夹路径
@Value("${tomato.upload-path}")
public String uploadPath;
//imgBaseUrl存的是"http://10.133.48.239:8081/img/",公网ip。
@Value("${tomato.img-baseurl}")
public String imgBaseUrl;
@Autowired
UserService userService;

@PostMapping("/upload")
    @ApiOperation("文件上传")
    public Result<String> upload(@RequestParam("files") MultipartFile files) {
        String fileName = null;
        String filePath;
        if (files == null) {
            throw new BaseException("未上传任何文件");
        }
        System.out.println("文件保存地址:" + uploadPath);
        //for (MultipartFile file : files) {
            //调用函数,返回文件存储路径
            fileName = renameFile(files, uploadPath);
            uploadToLocalServer(uploadPath+fileName, files, uploadPath);
            filePath=fileName;
        //}
        System.out.println("返回结果:"+filePath);
        return Result.success(filePath);
    }
  • 2.renameFile方法的作用是将图片重命名,生成该图片唯一的UUID。
public static String renameFile(MultipartFile file, String uploadPath) {
        //获取 原始文件名
        String originalFileName = file.getOriginalFilename();
        //System.out.println("原始文件名:" + originalFileName);
        //判断文件名是否有值 没有则抛出异常中断程序执行
        if (originalFileName == null) {
            throw new BaseException("未上传任何文件");
        }
        //使用UUID通用唯一识别码 + 后缀名的形式
        //设置唯一文件路径 防止文件名重复 出现覆盖的情况
        String fileName = UUID.randomUUID() + originalFileName.substring(originalFileName.lastIndexOf("."));
        //System.out.println("唯一文件名:" + fileName);
        // 指定文件保存的路径
        String filePath = uploadPath + File.separator + fileName;
        System.out.println("文件成功重命名并获得路径:" + filePath);
        return fileName;
    }
  • 3.uploadToLocalServer方法是将图片保存到本地文件夹,后续部署阶段只需要修改配置文件使其保存在服务器文件夹。
public static void uploadToLocalServer(String filePath, MultipartFile file, String uploadPath) {
        //根据上传路径创建文件夹File对象
        File saveAddress = new File(uploadPath);
        if (!saveAddress.exists()) {
            saveAddress.mkdirs();// 如果文件夹不存在 创建保存文件对应的文件夹
        }
        // 将上传的文件保存到指定路径
        try {
            file.transferTo(new File(filePath));
            System.out.println("成功");
        } catch (IOException e) {
            throw new BaseException("文件保存失败!");
        }
    }
  • 4.在WebMvcConfiguration配置类里添加资源映射;配置该资源映射使前端可以通过"http://10.133.48.239:8081/img/abcdefg.png"这样的路径访问服务器文件夹里的图片。
 /**
     * 设置静态资源映射
     *
     * @param registry
     */
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");

        // 使用file:前缀指定文件系统路径
        registry.addResourceHandler("/img/**")
                .addResourceLocations("file:" + filePath );

}
  • 5.小程序登录接口,后端点击登录访问该接口后,将数据存储到数据库,并封装返回。
    @Autowired
    private JwtProperties jwtProperties;
    @Autowired
    UserService userService;
    @PostMapping("/login")
    @ApiOperation("微信登录")
    public Result login(@RequestBody UserLoginDTO userLoginDTO) {
        User user=userService.wechatLogin(userLoginDTO);
        //生成JWT令牌
        Map<String,Object> claims=new HashMap<>();
        claims.put("userId",user.getId());
        String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);
        //封装成UserLoginVO对象返回
        //TODO 测试
        UserLoginVO userLoginVO = BeanUtil.copyProperties(user, UserLoginVO.class);
        userLoginVO.setToken(token);
        log.info(userLoginVO.toString());
        return Result.success(userLoginVO);
    }
  • 6.userService里的wechatLogin方法,主要思路是拿着appid和secret和前端给的code去访问微信接口,获取用户openId等信息。(详情查看微信小程序官方文档
//微信服务接口地址
    public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";

    @Autowired
    private WeChatProperties weChatProperties;
    @Value("${tomato.upload-path}")
    public String uploadPath;

    @Override
    public User wechatLogin(UserLoginDTO userLoginDTO) {
        //请求微信官方,获取包含openId等信息的字符串
        String s = getOpenId(userLoginDTO);
        //转成JSON对象,提取字段
        JSONObject jsonObject = JSON.parseObject(s);
        String openId = jsonObject.getString("openid");
        //如果openId不存在,抛出异常
        if (openId == null) {
            throw new BaseException("微信登录openId不存在!");
        }
        User user = lambdaQuery().eq(User::getOpenId, openId).one();
        getOrSetUser(user,userLoginDTO,openId);
        log.info("code="+userLoginDTO.getCode());
        //返回成功登录信息
        User theUser = lambdaQuery().eq(User::getOpenId, openId).one();
        return theUser;
    }
  • 7.getOpenId方法,获得微信官方接口返回的JSON字符串,解析得到openId。
private String getOpenId(UserLoginDTO userLoginDTO) {
        Map<String, String> map = new HashMap<>();
        map.put("appid", weChatProperties.getAppid());
        map.put("secret", weChatProperties.getSecret());
        map.put("js_code", userLoginDTO.getCode());
        map.put("grant_type", "authorization_code");
        String s = HttpClientUtil.doGet(WX_LOGIN, map);//返回封装的字符串
        return s;
    }
  • 8.getOrSetUser方法是对数据库进行操作,如果是新用户,就写入数据库,如果是老用户重新登录并上传了新头像和昵称,就需要更新记录。(未解决旧头像的删除问题)
  • 数据库里存储的头像只有"uuid.png",不包括URL前缀。
//返回用户信息或注册新用户
    public void getOrSetUser(User user,UserLoginDTO userLoginDTO,String openId) {
        //如果是新用户,自动注册
        if (user == null) {
            user = new User();
            user.setOpenId(openId);
            //裁剪图片url,获取最后的UUID部分。
            String[] parts = userLoginDTO.getAvatar().split("/");
            String lastPart = parts[parts.length-1];
            user.setAvatar(JSON.toJSONString(lastPart));
            user.setUsername(userLoginDTO.getUserName());
            //这里的是默认初始值,按照需求修改
            user.setGender(1L);
            user.setMajor("无");
            user.setPassword("123456");
            user.setStatus(0L);
            user.setPhone("无");
            save(user);
        }
        //老用户更新头像,忘记写更新昵称了。删除旧图片未实现。
        else {
            user.setUsername(userLoginDTO.getUserName());
            //裁剪图片url,获取最后的UUID部分。
            String[] parts = userLoginDTO.getAvatar().split("/");
            String lastPart = parts[parts.length-1];
            user.setAvatar(JSON.toJSONString(lastPart));
            updateById(user);
        }
    }
  • 关于代码中的jwtProperties和HttpClientUtil,都是一些比较通用的东西,需要自主学习理解(理解后cv大法)。

三、技术使用中遇到的问题和解决过程

  • 1.由于在数据库里存储的图片是JSON格式,后续取出数据需要对数据进行处理,包括转成字符串、拼接前缀使其成为可访问路径等。
//Pictures前拼接URL,参数为article的pictures--JSON
    public List<String> transPictures(String p) {
        List<String> pictures= JSON.parseArray(p,String.class);
        for (int i = 0; i < pictures.size(); i++) {
            pictures.set(i,imgBaseURL+pictures.get(i));
        }
        return pictures;
    }

    //avatar拼接URL,参数为user的avatar字符串--JSON
    public String transAvatar(String a) {
        String avatar=JSON.parseObject(a,String.class);
        avatar=imgBaseURL+avatar;
        return avatar;
    }
  • 2.由于upload方法只返回fileName而不是filePath,所以是无法访问的,之所以不在upload时就写入数据库是因为upload是一个通用接口,在文章模块也有图片需要上传,无法确定需要将图片保存在user表还是article表,所以只返回fileName;如果前端需要图片在上传时立刻回显,可以考虑在前端图片加上前缀。
  • 而微信登录并不需要图片立刻回显,其会生成一个临时的图片url,不需要使用upload传递的fileName。
  • 3.使用JSON格式存储多张图片时,每张图片前后都会有双引号"",需要后端代码中手动裁剪。

四、总结

  • 微信小程序登录只需要参照官方文档,从前端接受code等参数,访问微信接口,取得登录数据。
  • 而登录过程中涉及的头像上传,需要程序员自己实现,接收图片下载,回传,需要考虑数据库如何存储图片,如果在数据库里存储url前缀,在数据迁移时会带来问题。

五、参考文献

  • 12
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值