后台(java)接收前台文件上传,微信小程序文件上传

后台接收前台文件上传,微信小程序文件上传

因为初次进行一个小项目,出现不少问题,总结一些问题点,便于后期查阅。

一个简单的文件上传,前台提交文件,后台接收处理,ssm框架实现

前端页面用form表单提交,记得加上enctype="multipart/form-data"属性,用于定义传输编码,当然也可以用其他方式进行传输,这里只亲自测试了该种方式可行。

前端html代码:

	<form action="fileHandle/getExcel" enctype="multipart/form-data" method="post"> 
		<label>选择文件</label> 
		<input name="myfile" type="file"/><!-- name属性用于后台接收文件 -->
		<input type="submit" value="提交"/> 
	</form>

事先要配置好spring的配置文件,这里就不多说了。

后端接收文件:

多方百度后用了MultipartFile类接收,用该类需要导入jar包,我用了maven。后面打印文件信息要用到jxl的jar中的一些类,一起把代码粘贴了。
有些文章说还要导入io包,但是fileupload 1.3版本之后就兼容了io包,因此只需导一个就可以了。

maven代码为:

<!-- 文件传输  -->
	<dependency> 
		<groupId>commons-fileupload</groupId> 
		<artifactId>commons-fileupload</artifactId> 
		<version>1.3.3</version> 
	</dependency>
<!-- jxl -->
	<dependency>
		 
<think> 我们需要实现微信小程序的前端与Java后端的微信登录流程。微信登录流程主要涉及小程序端调用微信登录接口获取code,然后发送给后端,后端用code去微信服务器换取openid和session_key,然后后端可以自定义登录状态(如生成token)返回给小程序。 步骤: 1. 小程序端调用wx.login获取code。 2. 小程序端将code发送给后端服务器。 3. 后端服务器使用code、appid、appsecret等参数请求微信接口(https://api.weixin.qq.com/sns/jscode2session)获取openid和session_key。 4. 后端根据openid生成自定义登录态(例如token),并将openid和session_key(可能需要存储)与token关联存储(如Redis)。 5. 后端将token返回给小程序端。 6. 小程序端后续请求携带token,后端验证token并维护用户会话。 注意:session_key是微信小程序用于解密用户数据的,不能返回给前端。 下面分别给出小程序前端和Java后端的代码示例。 ### 小程序前端(JavaScript)代码示例 在小程序的登录按钮事件处理函数中: ```javascript // 小程序登录 wx.login({ success: res => { // 获取到code let code = res.code; // 将code发送给后端 wx.request({ url: 'https://your-backend-domain/api/login', // 替换为你的后端登录接口 method: 'POST', data: { code: code }, success: response => { // 后端返回的token,存储到本地 if (response.data.success) { let token = response.data.token; wx.setStorageSync('token', token); // 存储token // 后续请求可以携带这个token } } }) } }) ``` ### Java后端实现 首先,我们需要一个HTTP接口接收小程序传来的code,然后去微信服务器换取session_key和openid。 在Spring Boot中,我们可以创建一个Controller来处理登录请求。 步骤: 1. 添加依赖(Spring Web和HttpClient,这里使用RestTemplate) 2. 创建登录接口 依赖(pom.xml): ```xml <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 用于发送HTTP请求 --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </dependency> <!-- 如果需要使用Redis存储session,则添加spring-boot-starter-data-redis --> </dependencies> ``` 创建Controller: ```java import org.springframework.beans.factory.annotation.Value; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import java.util.HashMap; import java.util.Map; import java.util.UUID; @RestController public class LoginController { @Value("${wechat.appid}") private String appid; @Value("${wechat.secret}") private String secret; // 微信接口地址 private static final String WX_URL = "https://api.weixin.qq.com/sns/jscode2session?appid={appid}&secret={secret}&js_code={code}&grant_type=authorization_code"; @PostMapping("/api/login") public ResponseEntity<?> login(@RequestBody Map<String, String> data) { String code = data.get("code"); // 使用RestTemplate请求微信接口 RestTemplate restTemplate = new RestTemplate(); Map<String, String> params = new HashMap<>(); params.put("appid", appid); params.put("secret", secret); params.put("code", code); // 发送请求 WxResponse response = restTemplate.getForObject(WX_URL, WxResponse.class, params); // 检查微信返回的是否有错误 if (response.getErrcode() != null) { // 微信接口返回错误 return ResponseEntity.badRequest().body("登录失败: " + response.getErrmsg()); } // 从微信返回中获取openid和session_key String openid = response.getOpenid(); String sessionKey = response.getSession_key(); // 生成自定义登录态token String token = generateToken(openid); // 存储token与openid和session_key的关联(建议存Redis,并设置过期时间) // 例如:redisTemplate.opsForValue().set(token, openid, 2, TimeUnit.HOURS); // 同时,如果需要使用session_key解密用户信息,可以将会话密钥也存储起来,但注意安全性。 // 返回token给前端 Map<String, Object> result = new HashMap<>(); result.put("token", token); result.put("success", true); return ResponseEntity.ok(result); } private String generateToken(String openid) { // 这里简单生成一个token,实际生产环境可以使用JWT等机制 return UUID.randomUUID().toString(); } // 微信返回的数据结构 public static class WxResponse { private String openid; private String session_key; private String errcode; private String errmsg; // getter and setter public String getOpenid() { return openid; } public void setOpenid(String openid) { this.openid = openid; } public String getSession_key() { return session_key; } public void setSession_key(String session_key) { this.session_key = session_key; } public String getErrcode() { return errcode; } public void setErrcode(String errcode) { this.errcode = errcode; } public String getErrmsg() { return errmsg; } public void setErrmsg(String errmsg) { this.errmsg = errmsg; } } } ``` 在application.properties中配置微信的appid和secret: ```properties wechat.appid=你的小程序appid wechat.secret=你的小程序secret ``` ### 安全注意事项: 1. 微信的appsecret是敏感信息,不要泄露,不要放在前端。 2. session_key同样不要返回给前端,也不要在非加密信道传输。 3. 建议使用HTTPS进行通信。 以上代码提供了一个基本的微信登录流程。实际项目中,我们还需要考虑: - 异常处理 - 用户信息解密(如果需要获取用户信息,小程序端调用getUserInfo获取加密数据,然后后端用session_key解密) - 存储用户信息(将openid与系统用户绑定) - 使用更安全的token机制(如JWT) ### 用户信息解密(可选步骤) 如果小程序端需要获取用户信息(比如头像、昵称),则小程序端调用wx.getUserInfo,会返回加密数据(encryptedData)和初始向量(iv),然后发送给后端解密。 后端解密示例代码(需要用到session_key): ```java import org.apache.commons.codec.binary.Base64; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; public class WxDecryptUtil { public static String decrypt(String encryptedData, String sessionKey, String iv) { try { byte[] encryptedDataBytes = Base64.decodeBase64(encryptedData); byte[] sessionKeyBytes = Base64.decodeBase64(sessionKey); byte[] ivBytes = Base64.decodeBase64(iv); SecretKeySpec secretKeySpec = new SecretKeySpec(sessionKeyBytes, "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(ivBytes)); byte[] decrypted = cipher.doFinal(encryptedDataBytes); return new String(decrypted, StandardCharsets.UTF_8); } catch (Exception e) { e.printStackTrace(); return null; } } } ``` 解密后得到的是一个JSON字符串,包含用户信息。 注意:解密操作需要在后端进行,因为需要session_key。 至此,我们完成了微信小程序登录的全流程。 §§相关问题§§: 1. 如何在小程序端安全地存储token? 2. 后端如何验证token的有效性? 3. 微信小程序登录过程中,如何绑定用户的手机号? 4. 如何处理微信session_key过期的问题? </think># 小程序与 Java 后端实现微信登录方案 下面我将详细介绍如何实现小程序前台Java 后台的微信登录完整流程。 ## 整体流程 ```mermaid sequenceDiagram participant 小程序 participant Java后端 participant 微信服务器 小程序->>小程序: 调用wx.login()获取code 小程序->>Java后端: 发送code到登录API Java后端->>微信服务器: 使用code换取session_key和openid 微信服务器-->>Java后端: 返回session_key和openid Java后端->>Java后端: 生成自定义登录态token Java后端->>Java后端: 存储openid和session_key Java后端-->>小程序: 返回token给小程序 小程序->>小程序: 存储token到Storage 小程序->>Java后端: 后续请求携带token Java后端->>Java后端: 验证token并获取用户信息 ``` ## 实现步骤 ### 小程序端实现 ```javascript // pages/login/login.js // 微信登录方法 wxLogin() { // 1. 调用微信登录接口获取code wx.login({ success: (res) => { if (res.code) { // 2. 发送code到后端服务器 wx.request({ url: 'https://your-api-domain/api/miniapp/login', method: 'POST', data: { code: res.code }, success: (response) => { if (response.data.success) { const token = response.data.token; // 3. 存储自定义登录态token wx.setStorageSync('token', token); // 4. 获取用户信息(可选) this.getUserInfo(); } } }); } } }); }, // 获取用户信息(需要用户授权) getUserInfo() { wx.getUserProfile({ desc: '用于完善会员资料', success: (res) => { const userInfo = res.userInfo; // 发送用户信息到后端 wx.request({ url: 'https://your-api-domain/api/miniapp/userInfo', method: 'POST', header: { 'Authorization': 'Bearer ' + wx.getStorageSync('token') }, data: userInfo, success: (res) => { console.log('用户信息保存成功'); } }); } }); } ``` ### Java 后端实现 #### 1. 添加依赖(pom.xml) ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>4.9.1</version> </dependency> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.18.2</version> </dependency> ``` #### 2. 微信登录控制器(WeChatLoginController.java) ```java @RestController @RequestMapping("/api/miniapp") public class WeChatLoginController { @Value("${wechat.appid}") private String appid; @Value("${wechat.secret}") private String secret; @PostMapping("/login") public ResponseEntity<?> login(@RequestBody LoginRequest request) { // 1. 使用code换取session_key和openid Map<String, String> wxSession = getWxSession(request.getCode()); if (wxSession == null || wxSession.get("openid") == null) { return ResponseEntity.badRequest().body( Map.of("success", false, "message", "微信登录失败")); } String openid = wxSession.get("openid"); String sessionKey = wxSession.get("session_key"); // 2. 生成自定义登录态token String token = generateToken(openid); // 3. 存储openid和session_key(实际应存数据库) saveUserSession(openid, sessionKey, token); // 4. 返回token给小程序 return ResponseEntity.ok(Map.of( "success", true, "token", token, "openid", openid )); } // 获取微信session_key和openid private Map<String, String> getWxSession(String code) { String url = "https://api.weixin.qq.com/sns/jscode2session" + "?appid=" + appid + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code"; try { OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder().url(url).build(); Response response = client.newCall(request).execute(); if (response.isSuccessful() && response.body() != null) { String json = response.body().string(); return new ObjectMapper().readValue(json, Map.class); } } catch (Exception e) { e.printStackTrace(); } return null; } // 生成JWT token private String generateToken(String openid) { return JWT.create() .withIssuer("your-app-name") .withSubject(openid) .withExpiresAt(new Date(System.currentTimeMillis() + 7 * 24 * 60 * 60 * 1000)) // 7天有效期 .sign(Algorithm.HMAC256("your-secret-key")); } // 存储用户会话(简化版,实际应存数据库) private void saveUserSession(String openid, String sessionKey, String token) { // 实际实现应使用Redis或数据库存储 // 存储结构:token -> {openid, sessionKey} } // 接收用户信息 @PostMapping("/userInfo") public ResponseEntity<?> saveUserInfo( @RequestBody UserInfo userInfo, @RequestHeader("Authorization") String authHeader) { // 1. 验证token String token = authHeader.substring(7); // 去掉"Bearer " String openid = verifyToken(token); if (openid == null) { return ResponseEntity.status(401).body( Map.of("success", false, "message", "未授权访问")); } // 2. 保存用户信息到数据库 userInfo.setOpenid(openid); userService.saveOrUpdate(userInfo); return ResponseEntity.ok(Map.of("success", true)); } // 验证JWT token private String verifyToken(String token) { try { DecodedJWT jwt = JWT.require(Algorithm.HMAC256("your-secret-key")) .build() .verify(token); return jwt.getSubject(); } catch (Exception e) { return null; } } // 内部类定义 @Data public static class LoginRequest { private String code; } @Data public static class UserInfo { private String openid; private String nickName; private String avatarUrl; private Integer gender; private String country; private String province; private String city; private String language; } } ``` ### 3. 配置文件(application.properties) ```properties # 微信小程序配置 wechat.appid=你的小程序AppID wechat.secret=你的小程序AppSecret # JWT配置 jwt.secret-key=your-secret-key jwt.expiration=604800 # 7天() ``` ## 关键点解释 1. **小程序端流程**: - 调用 `wx.login()` 获取临时登录凭证 code - 将 code 发送到 Java 后端 - 接收后端返回的 token 并存储 - (可选)获取用户信息并发送到后端 2. **Java后端流程**: - 接收小程序传来的 code - 调用微信接口换取 session_key 和 openid - 生成自定义登录态 token(使用 JWT) - 存储用户会话信息(openid 和 session_key) - 返回 token 给小程序 - 验证后续请求中的 token 3. **安全考虑**: - 使用 HTTPS 传输数据 - 敏感信息(AppSecret)存储在服务器端 - 使用 JWT 作为无状态认证机制 - session_key 不应返回给小程序端 4. **会话管理**: - 实际应使用 Redis 或数据库存储 session_key - session_key 用于解密用户敏感信息 - token 有效期应合理设置(通常 7-30 天) ## 完善建议 1. **错误处理**: - 处理微信接口返回的错误码 - 添加重试机制(如 session_key 失效时) - 记录详细的日志 2. **会话管理**: ```java // Redis存储实现示例 @Autowired private RedisTemplate<String, Object> redisTemplate; private void saveUserSession(String openid, String sessionKey, String token) { Map<String, String> session = new HashMap<>(); session.put("openid", openid); session.put("session_key", sessionKey); session.put("token", token); // 存储到Redis,有效期7天 redisTemplate.opsForValue().set("session:" + openid, session, 7, TimeUnit.DAYS); redisTemplate.opsForValue().set("token:" + token, openid, 7, TimeUnit.DAYS); } ``` 3. **用户绑定**: - 将微信 openid 与系统用户 ID 关联 - 支持同一用户多设备登录 - 实现用户信息同步机制
评论 8
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值