-
一、通用Mapper中的方法解析方法功能说明int countByExample(UserExample example) thorws SQLException按条件计数int deleteByPrimaryKey(Integer id) thorws SQLException按主键删除int deleteByExample(UserExample example) thorws SQLException按条件查询String/Integer insert(User record) thorws SQLException插入数据(返回值为ID)User selectByPrimaryKey(Integer id) thorws SQLException按主键查询List selectByExample(UserExample example) thorws SQLException按条件查询List selectByExampleWithBLOGs(UserExample example) thorws SQLException按条件查询(包括BLOB字段)。只有当数据表中的字段类型有为二进制的才会产生。int updateByPrimaryKey(User record) thorws SQLException按主键更新int updateByPrimaryKeySelective(User record) thorws SQLException按主键更新值不为null的字段int updateByExample(User record, UserExample example) thorws SQLException按条件更新int updateByExampleSelective(User record, UserExample example) thorws SQLException按条件更新值不为null的字段二、Example实例解析mybatis的逆向工程中会生成实例及实例对应的example,example用于添加条件,相当where后面的部分import tk.mybatis.mapper.entity.Example; Example example = new Example(JavaBean.class); Example.Criteria criteria = example.createCriteria();方法说明example.setOrderByClause(“字段名 ASC”);添加升序排列条件,DESC为降序example.setDistinct(false)去除重复,boolean型,true为选择不重复的记录。criteria.andXxxIsNull添加字段xxx为null的条件criteria.andXxxIsNotNull添加字段xxx不为null的条件criteria.andXxxEqualTo(value)添加xxx字段等于value条件criteria.andXxxNotEqualTo(value)添加xxx字段不等于value条件criteria.andXxxGreaterThan(value)添加xxx字段大于value条件criteria.andXxxGreaterThanOrEqualTo(value)添加xxx字段大于等于value条件criteria.andXxxLessThan(value)添加xxx字段小于value条件criteria.andXxxLessThanOrEqualTo(value)添加xxx字段小于等于value条件criteria.andXxxIn(List<?>)添加xxx字段值在List<?>条件criteria.andXxxNotIn(List<?>)添加xxx字段值不在List<?>条件criteria.andXxxLike(“%”+value+”%”)添加xxx字段值为value的模糊查询条件criteria.andXxxNotLike(“%”+value+”%”)添加xxx字段值不为value的模糊查询条件criteria.andXxxBetween(value1,value2)添加xxx字段值在value1和value2之间条件criteria.andXxxNotBetween(value1,value2)添加xxx字段值不在value1和value2之间条件三、使用案例1.查询① selectByPrimaryKey() 按主键查询//相当于:select * from user where id = 100; User user = UserMapper.selectByPrimaryKey(100); ② selectByExample() 和 selectByExampleWithBLOGs()//相当于:select * from user where username = 'wyw' // and username is null order by username asc,email desc UserExample example = new UserExample(); Criteria criteria = example.createCriteria(); criteria.andUsernameEqualTo("wyw"); criteria.andUsernameIsNull(); example.setOrderByClause("username asc,email desc"); Listlist = XxxMapper.selectByExample(example);2.插入数据①insert()//相当于:insert into user(ID,username,password,email) values //('dsfgsdfgdsfgds','jack','1234','hello@126.com'); User user = new User(); user.setId("dsfgsdfgdsfgds"); user.setUsername("jack"); user.setPassword("1234") user.setEmail("hello@163.com"); XxxMapper.insert(user);3.更新数据①updateByPrimaryKey()//相当于:update user set username='rose', password='5678', //email='hello@163.com' where id='a01' User user =new User(); user.setId("a01"); user.setUsername("rose"); user.setPassword("5678"); user.setEmail("hello@163.com"); XxxMapper.updateByPrimaryKey(user);②updateByPrimaryKeySelective()//相当于:update user set password='7890' where id='a01' User user = new User(); user.setId("a01"); user.setPassword("7890"); XxxMapper.updateByPrimaryKey(user);③ updateByExample() 和 updateByExampleSelective()//相当于:update user set password='6666' where username='jack' UserExample example = new UserExample(); Criteria criteria = example.createCriteria(); criteria.andUsernameEqualTo("jack"); User user = new User(); user.setPassword("6666"); XxxMapper.updateByPrimaryKeySelective(user,example);updateByExample()更新所有的字段,包括字段为null的也更新建议使用 updateByExampleSelective()更新想更新的字段4.删除数据①deleteByPrimaryKey()//相当于:delete from user where id=1 XxxMapper.deleteByPrimaryKey(1); ②deleteByExample()//相当于:delete from user where username='jack' UserExample example = new UserExample(); Criteria criteria = example.createCriteria(); criteria.andUsernameEqualTo("jack"); XxxMapper.deleteByExample(example);5.查询数据数量①countByExample()//相当于:select count(*) from user where username='jack' UserExample example = new UserExample(); Criteria criteria = example.createCriteria(); criteria.andUsernameEqualTo("jack"); int count = XxxMapper.countByExample(example);原文链接:https://www.cnblogs.com/tian-ci/p/10543089.html
-
tk.MyBatis常用Mapper接口及Example方法说明一、通用Mapper中的方法解析方法功能说明int countByExample(UserExample example) thorws SQLException按条件计数int deleteByPrimaryKey(Integer id) thorws SQLException按主键删除int deleteByExample(UserExample example) thorws SQLException按条件查询String/Integer insert(User record) thorws SQLException插入数据(返回值为ID)User selectByPrimaryKey(Integer id) thorws SQLException按主键查询List selectByExample(UserExample example) thorws SQLException按条件查询List selectByExampleWithBLOGs(UserExample example) thorws SQLException按条件查询(包括BLOB字段)。只有当数据表中的字段类型有为二进制的才会产生。int updateByPrimaryKey(User record) thorws SQLException按主键更新int updateByPrimaryKeySelective(User record) thorws SQLException按主键更新值不为null的字段int updateByExample(User record, UserExample example) thorws SQLException按条件更新int updateByExampleSelective(User record, UserExample example) thorws SQLException按条件更新值不为null的字段二、Example实例解析mybatis的逆向工程中会生成实例及实例对应的example,example用于添加条件,相当where后面的部分import tk.mybatis.mapper.entity.Example; Example example = new Example(JavaBean.class); Example.Criteria criteria = example.createCriteria();1234方法说明example.setOrderByClause(“字段名 ASC”);添加升序排列条件,DESC为降序example.setDistinct(false)去除重复,boolean型,true为选择不重复的记录。criteria.andXxxIsNull添加字段xxx为null的条件criteria.andXxxIsNotNull添加字段xxx不为null的条件criteria.andXxxEqualTo(value)添加xxx字段等于value条件criteria.andXxxNotEqualTo(value)添加xxx字段不等于value条件criteria.andXxxGreaterThan(value)添加xxx字段大于value条件criteria.andXxxGreaterThanOrEqualTo(value)添加xxx字段大于等于value条件criteria.andXxxLessThan(value)添加xxx字段小于value条件criteria.andXxxLessThanOrEqualTo(value)添加xxx字段小于等于value条件criteria.andXxxIn(List<?>)添加xxx字段值在List<?>条件criteria.andXxxNotIn(List<?>)添加xxx字段值不在List<?>条件criteria.andXxxLike(“%”+value+”%”)添加xxx字段值为value的模糊查询条件criteria.andXxxNotLike(“%”+value+”%”)添加xxx字段值不为value的模糊查询条件criteria.andXxxBetween(value1,value2)添加xxx字段值在value1和value2之间条件criteria.andXxxNotBetween(value1,value2)添加xxx字段值不在value1和value2之间条件使用案例1.查询① selectByPrimaryKey() 按主键查询//相当于:select * from user where id = 100; User user = UserMapper.selectByPrimaryKey(100); 12② selectByExample() 和 selectByExampleWithBLOGs()//相当于:select * from user where username = 'wyw' // and username is null order by username asc,email desc UserExample example = new UserExample(); Criteria criteria = example.createCriteria(); criteria.andUsernameEqualTo("wyw"); criteria.andUsernameIsNull(); example.setOrderByClause("username asc,email desc"); Listlist = XxxMapper.selectByExample(example);123456782.插入数据①insert()//相当于:insert into user(ID,username,password,email) values //('dsfgsdfgdsfgds','jack','1234','hello@126.com'); User user = new User(); user.setId("dsfgsdfgdsfgds"); user.setUsername("jack"); user.setPassword("1234") user.setEmail("hello@163.com"); XxxMapper.insert(user);123456783.更新数据①updateByPrimaryKey()//相当于:update user set username='rose', password='5678', //email='hello@163.com' where id='a01' User user =new User(); user.setId("a01"); user.setUsername("rose"); user.setPassword("5678"); user.setEmail("hello@163.com"); XxxMapper.updateByPrimaryKey(user);12345678②updateByPrimaryKeySelective()//相当于:update user set password='7890' where id='a01' User user = new User(); user.setId("a01"); user.setPassword("7890"); XxxMapper.updateByPrimaryKey(user);12345③ updateByExample() 和 updateByExampleSelective()//相当于:update user set password='6666' where username='jack' UserExample example = new UserExample(); Criteria criteria = example.createCriteria(); criteria.andUsernameEqualTo("jack"); User user = new User(); user.setPassword("6666"); XxxMapper.updateByPrimaryKeySelective(user,example); updateByExample()更新所有的字段,包括字段为null的也更新 建议使用 updateByExampleSelective()更新想更新的字段124.删除数据①deleteByPrimaryKey()//相当于:delete from user where id=1XxxMapper.deleteByPrimaryKey(1);②deleteByExample()//相当于:delete from user where username='jack' UserExample example = new UserExample(); Criteria criteria = example.createCriteria(); criteria.andUsernameEqualTo("jack"); XxxMapper.deleteByExample(example);5.查询数据数量①countByExample()//相当于:select count(*) from user where username='jack' UserExample example = new UserExample(); Criteria criteria = example.createCriteria(); criteria.andUsernameEqualTo("jack"); int count = XxxMapper.countByExample(example);原文链接:https://blog.csdn.net/qq_33578833/article/details/104531530
-
1.准备工作 移动应用微信登录是基于OAuth2.0协议标准 构建的微信OAuth2.0授权登录系统。 在进行微信OAuth2.0授权登录接入之前,在微信开放平台注册开发者帐号,并拥有一个已审核通过的移动应用,并获得相应的AppID和AppSecret,申请微信登录且通过审核后,可开始接入流程。 2.授权流程说明 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数; 通过code参数加上AppID和AppSecret等,通过API换取access_token; 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。 3. 获取access_token时序图 4. maven依赖 commons-httpclient commons-httpclient 3.0.1 org.springframework.boot spring-boot-devtools org.apache.commons commons-io 1.3.2 org.apache.commons commons-lang3 3.4 org.apache.httpcomponents httpclient 4.3.2 com.alibaba fastjson 1.2.38 5.在application.yml文件中配置你的 #第三方微信登录(用你自己的) #appID App的ID #appSecret weixinconfig: weixinappID: wxf7865421a3c4d5f weixinappSecret: 6cdbe6d4ce6sbcf0593c913d8a0ce12 创建配置类 import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @Component @ConfigurationProperties(prefix="weixinconfig") public class WeixinLoginProperties { private String weixinappID; // 商户appid private String weixinappSecret; // 私钥 pkcs8格式的 public String getWeixinappID() { return weixinappID; } public void setWeixinappID(String weixinappID) { this.weixinappID = weixinappID; } public String getWeixinappSecret() { return weixinappSecret; } public void setWeixinappSecret(String weixinappSecret) { this.weixinappSecret = weixinappSecret; } } 6.第一步:请求CODE 这一步客户端会把code传过来 ,不用你操心 7.第二步:通过code获取access_token package io.renren.api.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.configurationprocessor.json.JSONException; import org.springframework.boot.configurationprocessor.json.JSONObject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import io.renren.api.dao.TpAccesstokenMapper; import io.renren.api.dao.TpUsersMapper; import io.renren.api.entity.TpAccesstoken; import io.renren.api.entity.TpAccesstokenExample; import io.renren.api.entity.TpAccumulativeAward; import io.renren.api.entity.TpUsers; import io.renren.api.entity.TpUsersExample; import io.renren.api.properties.WeixinLoginProperties; import io.renren.api.service.TpAccesstokenService; import io.renren.api.service.TpAccumulativeAwardService; import io.renren.api.service.TpUsersService; import io.renren.common.utils.R; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.math.BigDecimal; import java.net.URI; import java.util.List; import javax.annotation.Resource; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; /** * 第三方微信登录 * @author Administrator * */ @SuppressWarnings("deprecation") @Controller @RequestMapping("/api") public class WeXinController { //微信公众平台申请 //应用唯一标识,在微信开放平台提交应用审核通过后获得 appID //应用密钥AppSecret,在微信开放平台提交应用审核通过后获得 appSecret //TpAccesstoken 用来保存微信返回的用户信息oppid等 @Resource private WeixinLoginProperties weixinLoginProperties; @Autowired TpUsersService tpUsersService; @Autowired TpUsersMapper tpUsersMapper; @Autowired TpAccesstokenService tpAccesstokenService; @Autowired TpAccesstokenMapper tpAccesstokenMapper; @Autowired TpAccumulativeAwardService tpAccumulativeAwardService; /** * 获取accessToken,该步骤返回的accessToken期限为一个月 * * @param code * @return * @throws Exception */ @SuppressWarnings("all") @RequestMapping("weixincallback") @ResponseBody public R getAccessToken(String code) throws Exception { String appID = weixinLoginProperties.getWeixinappID(); String appSecret = weixinLoginProperties.getWeixinappSecret(); String accesstoken; String openid = null; String refreshtoken; int expiresIn; String unionid;//可通过获取用户基本信息中的unionid来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号, //用户的unionid是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。 if (code != null) { System.out.println(code); } String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid="+appID+"&secret="+appSecret+"&code="+code+"&grant_type=authorization_code"; URI uri = URI.create(url); org.apache.http.client.HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(uri); HttpResponse response; try { response = client.execute(get); if (response.getStatusLine().getStatusCode() == 200) { HttpEntity entity = response.getEntity(); BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8")); StringBuilder sb = new StringBuilder(); for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) { sb.append(temp); } JSONObject object = new JSONObject(sb.toString().trim()); System.out.println("object:"+object); accesstoken = object.getString("access_token"); System.out.println("accesstoken:"+accesstoken); openid = object.getString("openid"); System.out.println("openid:"+openid); refreshtoken = object.getString("refresh_token"); System.out.println("refreshtoken:"+refreshtoken); expiresIn = (int) object.getLong("expires_in"); unionid = object.getString("unionid"); // 将用户信息保存到数据库 //1.先查询用户是否是第一次第三方登录如果是第一次那么是将用户信息添加到数据库 如果不是那么是更新到数据库 TpUsers userInfo = getUserInfo(accesstoken,openid); Integer userId = userInfo.getUserId(); TpAccesstokenExample example = new TpAccesstokenExample(); example.createCriteria().andOpenidEqualTo(openid); List list = tpAccesstokenMapper.selectByExample(example); if(list!=null&&list.size()>0) { //那么该用户不是第一次 执行更新操作 TpAccesstoken tpAccesstoken = list.get(0); tpAccesstoken.setAccesstoken(accesstoken); tpAccesstoken.setUserId(userId); tpAccesstoken.setExpiresIn(expiresIn); tpAccesstoken.setOpenid(openid); tpAccesstoken.setRefreshtoken(refreshtoken); tpAccesstokenService.save(tpAccesstoken); }else { TpAccesstoken tpAccesstoken=new TpAccesstoken(); tpAccesstoken.setUserId(userId); tpAccesstoken.setAccesstoken(accesstoken); tpAccesstoken.setExpiresIn(expiresIn); tpAccesstoken.setOpenid(openid); tpAccesstoken.setRefreshtoken(refreshtoken); tpAccesstokenService.save(tpAccesstoken); //tpAccesstokenService.insertAccesstoken(userId,openid, accesstoken, expiresIn, refreshtoken); } //refreshAccessToken(openid); System.out.println("Openid"+userInfo.getOpenid()); return R.ok().put("userInfo", userInfo).put("openid", openid); } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (JSONException e) { e.printStackTrace(); } return R.ok().put("openid", openid); } /* * * 1 { 2 "access_token":"ACCESS_TOKEN", 3 "expires_in":7200, 4 * "refresh_token":"REFRESH_TOKEN", 5 "openid":"OPENID", 6 "scope":"SCOPE", 7 * "unionid":"o6_bmasdasdsad6_2sgVt7hMZOPfL" 8 } 复制代码 复制代码 参数 说明 access_token * 接口调用凭证 expires_in access_token 接口调用凭证超时时间,单位(秒) refresh_token * 用户刷新access_token openid 授权用户唯一标识 scope 用户授权的作用域,使用逗号(,)分隔 unionid * 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。 * */ /** * 刷新token * * @param openID * @return */ @SuppressWarnings({ "unused", "resource" }) private void refreshAccessToken(String openid) { String refreshtoken=null; TpAccesstoken tpAccesstoken=new TpAccesstoken(); String appID = weixinLoginProperties.getWeixinappID(); String appSecret = weixinLoginProperties.getWeixinappSecret(); TpAccesstokenExample example = new TpAccesstokenExample(); example.createCriteria().andOpenidEqualTo(openid); List list = tpAccesstokenMapper.selectByExample(example); if(list!=null&&list.size()>0) { tpAccesstoken = list.get(0); refreshtoken = tpAccesstoken.getRefreshtoken(); } String uri = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid="+appID+"&grant_type=refresh_token&refresh_token="+refreshtoken; org.apache.http.client.HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(URI.create(uri)); try { HttpResponse response = client.execute(get); if (response.getStatusLine().getStatusCode() == 200) { BufferedReader reader = new BufferedReader( new InputStreamReader(response.getEntity().getContent(), "UTF-8")); StringBuilder builder = new StringBuilder(); for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) { builder.append(temp); } JSONObject object = new JSONObject(builder.toString().trim()); String accessToken = object.getString("access_token"); String refreshToken = object.getString("refresh_token"); openid = object.getString("openid"); int expires_in = (int) object.getLong("expires_in"); tpAccesstoken.setAccesstoken(accessToken); tpAccesstoken.setExpiresIn(expires_in); tpAccesstoken.setOpenid(openid); tpAccesstoken.setRefreshtoken(refreshToken); tpAccesstokenService.save(tpAccesstoken); } } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * 根据accessToken获取用户信息 * * @param accessToken * @param openID * @return * @throws Exception */ @SuppressWarnings({ "unused", "resource" }) public TpUsers getUserInfo(String accessToken, String openID) throws Exception { String appID = weixinLoginProperties.getWeixinappID(); String appSecret = weixinLoginProperties.getWeixinappSecret(); String uri = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openID; org.apache.http.client.HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(URI.create(uri)); try { HttpResponse response = client.execute(get); if (response.getStatusLine().getStatusCode() == 200) { BufferedReader reader = new BufferedReader( new InputStreamReader(response.getEntity().getContent(), "UTF-8")); StringBuilder builder = new StringBuilder(); for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) { builder.append(temp); } JSONObject object = new JSONObject(builder.toString().trim()); String country = object.getString("country"); String nikeName = object.getString("nickname"); String unionid = object.getString("unionid"); String province = object.getString("province"); String city = object.getString("city"); String openid = object.getString("openid"); String sex = object.getString("sex"); String headimgurl = object.getString("headimgurl"); String language = object.getString("language"); BigDecimal bigDecimal=new BigDecimal(0.0); TpUsersExample example=new TpUsersExample(); example.createCriteria().andOpenidEqualTo(openid); List list = tpUsersMapper.selectByExample(example); if(list!=null&&list.size()>0) { TpUsers tpUsers = list.get(0); System.out.println("---------"); return tpUsers; }else { TpUsers tpUsers=new TpUsers(); tpUsers.setOauth("wx"); tpUsers.setOpenid(openid); tpUsers.setUnionid(unionid); tpUsers.setUserName(nikeName); tpUsers.setUserMoney(bigDecimal); tpUsersService.save(tpUsers); System.out.println("+++++++"); return tpUsers; } } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (JSONException e) { e.printStackTrace(); } return null; } @RequestMapping("/isaccesstoken") @SuppressWarnings({ "resource" }) private boolean isAccessTokenIsInvalid(String accessToken,String openID) { String url = "https://api.weixin.qq.com/sns/auth?access_token=" + accessToken + "&openid=" + openID; URI uri = URI.create(url); org.apache.http.client.HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(uri); HttpResponse response; try { response = client.execute(get); if (response.getStatusLine().getStatusCode() == 200) { HttpEntity entity = response.getEntity(); BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8")); StringBuilder sb = new StringBuilder(); for (String temp = reader.readLine(); temp != null; temp = reader.readLine()) { sb.append(temp); } JSONObject object = new JSONObject(sb.toString().trim()); /* { "errcode":0,"errmsg":"ok" } 错误的Json返回示例: { "errcode":40003,"errmsg":"invalid openid" }*/ int errorCode = object.getInt("errcode"); if (errorCode == 0) { return true; } } } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (JSONException e) { e.printStackTrace(); } return false; } } 获取第一步的code后,请求以下链接进行refresh_token: https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN 参数说明 参数 是否必须 说明 appid 是 应用唯一标识 grant_type 是 填refresh_token refresh_token 是 填写通过access_token获取到的refresh_token参数 返回说明 正确的返回: { "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" } 参数 说明 access_token 接口调用凭证 expires_in access_token接口调用凭证超时时间,单位(秒) refresh_token 用户刷新access_token openid 授权用户唯一标识 scope 用户授权的作用域,使用逗号(,)分隔 错误返回样例: {"errcode":40030,"errmsg":"invalid refresh_token"} 刷新或续期access_token使用 接口说明 access_token是调用授权关系接口的调用凭证,由于access_token有效期(目前为2个小时)较短,当access_token超时后,可以使用refresh_token进行刷新,access_token刷新结果有两种: 1.若access_token已超时,那么进行refresh_token会获取一个新的access_token,新的超时时间; 2.若access_token未超时,那么进行refresh_token不会改变access_token,但超时时间会刷新,相当于续期access_token。 refresh_token拥有较长的有效期(30天)且无法续期,当refresh_token失效的后,需要用户重新授权后才可以继续获取用户头像昵称。 请求方法 使用/sns/oauth2/access_token接口获取到的refresh_token进行以下接口调用: http请求方式: GET https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN 参数说明 参数 是否必须 说明 appid 是 应用唯一标识 grant_type 是 填refresh_token refresh_token 是 填写通过access_token获取到的refresh_token参数 返回说明 正确的返回: { "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" } 参数 说明 access_token 接口调用凭证 expires_in access_token接口调用凭证超时时间,单位(秒) refresh_token 用户刷新access_token openid 授权用户唯一标识 scope 用户授权的作用域,使用逗号(,)分隔 错误返回样例: { "errcode":40030,"errmsg":"invalid refresh_token" } 获取用户个人信息(UnionID机制) 接口说明 此接口用于获取用户个人信息。开发者可通过OpenID来获取用户基本信息。特别需要注意的是,如果开发者拥有多个移动应用、网站应用和公众帐号,可通过获取用户基本信息中的unionid来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号,用户的unionid是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。请注意,在用户修改微信头像后,旧的微信头像URL将会失效,因此开发者应该自己在获取用户信息后,将头像图片保存下来,避免微信头像URL失效后的异常情况。 请求说明 http请求方式: GET https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID 参数说明 参数 是否必须 说明 access_token 是 调用凭证 openid 是 普通用户的标识,对当前开发者帐号唯一 lang 否 国家地区语言版本,zh_CN 简体,zh_TW 繁体,en 英语,默认为zh-CN 返回说明 正确的Json返回结果: { "openid":"OPENID", "nickname":"NICKNAME", "sex":1, "province":"PROVINCE", "city":"CITY", "country":"COUNTRY", "headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0", "privilege":[ "PRIVILEGE1", "PRIVILEGE2" ], "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL" } 参数 说明 openid 普通用户的标识,对当前开发者帐号唯一 nickname 普通用户昵称 sex 普通用户性别,1为男性,2为女性 province 普通用户个人资料填写的省份 city 普通用户个人资料填写的城市 country 国家,如中国为CN headimgurl 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空 privilege 用户特权信息,json数组,如微信沃卡用户为(chinaunicom) unionid 用户统一标识。针对一个微信开放平台帐号下的应用,同一用户的unionid是唯一的。 建议: 开发者最好保存unionID信息,以便以后在不同应用之间进行用户信息互通。 错误的Json返回示例: { "errcode":40003,"errmsg":"invalid openid" } 工具类 package io.renren.common.utils; import java.util.HashMap; import java.util.Map; /** * 返回数据 * * @author chenshun * @email sunlightcs@gmail.com * @date 2016年10月27日 下午9:59:27 */ public class R extends HashMap { private static final long serialVersionUID = 1L; public R() { put("code", 0); put("msg", "success"); } public static R error() { return error(500, "未知异常,请联系管理员"); } public static R error(String msg) { return error(500, msg); } public static R error(int code, String msg) { R r = new R(); r.put("code", code); r.put("msg", msg); return r; } public static R ok(String msg) { R r = new R(); r.put("msg", msg); return r; } public static R ok(Map map) { R r = new R(); r.putAll(map); return r; } public static R ok() { return new R(); } @Override public R put(String key, Object value) { super.put(key, value); return this; } } 原文链接:https://blog.csdn.net/weixin_42694286/article/details/84344786
-
一、前言 我在网上找了很多关于识别一维码和二维码的资料,总结一下,手机端目前能找到ZXing,ZBar都只能支持单个一维码,单个和多个二维码的识别,当图片有二维码和一维码同时存在,也只能识别二维码,而且ZXing还在持续更新中,所以最好的选择是ZXing。二、代码和使用/*** 扫描的工具类-------一维码二维码(识别图片)* **/public class BarcodeUtil {/**** 获取图片的一维码----目前只支持一个条形码 filename --图片的绝对路径* */public static String getOneBarcode(String filename, Context context) {String onebarcode = "";Bitmap img = BitmapUtils.getCompressedBitmap(filename);BitmapDecoder decoder = new BitmapDecoder(context);Result result = decoder.getRawResult(img);String resP = "";if (result != null&& codeType(DecodeFormatManager.ONE_D_FORMATS,result.getBarcodeFormat())) {resP = "|" + result.getResultPoints()[1].getX() + "|"+ result.getResultPoints()[1].getY() + "|";onebarcode = result.getText() + resP;}return onebarcode;}/**** 获取图片的二维码----目前可支持多个二维码 filename --图片的绝对路径* */public static String getTwoBarcode(String filename) {String twobarcode = "";Bitmap img = BitmapUtils.getCompressedBitmap(filename);int[] intArray = new int[img.getWidth() * img.getHeight()];img.getPixels(intArray, 0, img.getWidth(), 0, 0, img.getWidth(),img.getHeight());LuminanceSource source = new RGBLuminanceSource(img.getWidth(),img.getHeight(), intArray);BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));QRCodeMultiReader odecoder = new QRCodeMultiReader();Result[] results;String resP = "";try {results = odecoder.decodeMultiple(bitmap);if (results != null) {for (Result result2 : results) {if (result2 != null&& codeType(DecodeFormatManager.QR_CODE_FORMATS,result2.getBarcodeFormat())) {resP = "|" + result2.getResultPoints()[1].getX() + "|"+ result2.getResultPoints()[1].getY() + "|";twobarcode += result2.getText() + resP;}}}} catch (NotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}return twobarcode;}/**** 确认扫描的** */private static boolean codeType(final Collection type,BarcodeFormat barcodeFormat) {for (BarcodeFormat barcode : type) {if (barcodeFormat.equals(barcode)) {return true;}}return false;}}说明 :我这个同时返回了一维码或二维码包含的信息还有它所在位置的左上角的那个坐标点。(result.getResultPoints()[1].getX() +result.getResultPoints()[1].getY() 这是左上角那个点的坐标) 一维码只返回两个坐标,二维码返回了4个,根据你的需要去取。重点说明:对多个二维码的识别,需要使用QRCodeMultiReader去识别,很多地方找不到这个类的具体使用方法,你需要下载一个比较新版本的ZXing包,里面才有这方法。其他相关的一些工具类,你也可以在对应的里面找到。因为关于ZXing的使用很容易在GitHub等地方找到demo,但是对多个扫描的二维码的识别就基本没有使用的例子,使用的方法都提供了,但没有直接的使用总结,所以我这里贴的就是我的一个简单的使用和说明,希望可以帮到你。原文链接:https://juejin.cn/post/6844903549487284238
-
公司是做广告服务的,运转模式一句话就是:在车内设备上播放广告主投放的广告,并获取收益,现在有个需求是,要统计广告主投放的广告里面的二维码的扫码量,进行数据分析,为后面人物画像做准备,因多种事业环境因素,让广告主提供统计数据或者提供链接给我们,我们生成二维码等,根本不太可能,所以,只能自己撸启袖子干! 我疏导了下流程,如下: 1.广告审核的时候,判断图片是否包含二维码 2.包含二维码的图片,对原图片里面二维码进行识别并定位 3.获取原图片里二维码的信息和坐标信息(x,y,w,h),并保存起来 4.开发一个接口,这个接口可以理解为新二维码的链接路径 5.根据坐标使用上面接口如(www.abc?taskId=10&imei=2ej3dd)生成新二维码并推送到设备 6.设备获取推送的包含二维码的图片并根据后台分发的坐标信息生成新的二维码 7.设备根据坐标和其他需要携带的参数生成新二维码 8.用户扫码跳转到接口路径,接口获得相关参数记录扫码量并重定向到原图片里面二维码路径 至此,大功告成! 一个东西的技术实现,都是站在前人的肩膀上去累积,优化,总结的,我大概在网上看了下,貌似没有人遇到这种需求,参考了opencv java版本的代码,毕竟不是做图像识别的,这方面的知识有限,所以用了zxing实现.于是自己硬着头皮上,基本实现了我们的业务需求,但,二维码的坐标识别还是有些许的差别,还是把代码分享出来,起抛砖引玉的作用,同时,也希望大家能够在这个基础上进行优化... 以下为代码片段 先加入maven依赖: com.google.zxing core 3.3.3 com.google.zxing javase 3.3.3 下面为完整java代码: package com.bpb.qrcode; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; import javax.imageio.ImageIO; import com.google.zxing.Binarizer; import com.google.zxing.BinaryBitmap; import com.google.zxing.DecodeHintType; import com.google.zxing.EncodeHintType; import com.google.zxing.LuminanceSource; import com.google.zxing.MultiFormatReader; import com.google.zxing.NotFoundException; import com.google.zxing.Result; import com.google.zxing.ResultPoint; import com.google.zxing.client.j2se.BufferedImageLuminanceSource; import com.google.zxing.common.HybridBinarizer; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import lombok.extern.slf4j.Slf4j; @Slf4j public class QRCodeTools3 { /** * * @Title: deEncodeByPath * @Description: 替换原图片里面的二维码 * @param @param filePath * @param @param newPath 设定文件 * @return void 返回类型 * @throws */ public static void deEncodeByPath(String filePath, String newPath) { // 原图里面二维码的url String originalURL = null; try { // 将远程文件转换为流 BufferedImage readImage = ImageIO.read(new File(filePath)); LuminanceSource source = new BufferedImageLuminanceSource(readImage); Binarizer binarizer = new HybridBinarizer(source); BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer); Map hints = new HashMap(); hints.put(DecodeHintType.CHARACTER_SET, "UTF-8"); Result result = null; result = new MultiFormatReader().decode(binaryBitmap, hints); originalURL = result.getText(); // 解码 ResultPoint[] resultPoint = result.getResultPoints(); System.out.println("原二维码里面的url:" + originalURL + ",\npoints1: " + resultPoint[0] + ",\npoints2: " + resultPoint[1] + ",\npoints2: " + resultPoint[2] + ",\npoints2: " + resultPoint[3]); // 获得二维码坐标 float point1X = resultPoint[0].getX(); float point1Y = resultPoint[0].getY(); float point2X = resultPoint[1].getX(); float point2Y = resultPoint[1].getY(); // 替换二维码的图片文件路径 BufferedImage writeFile = ImageIO.read(new File(newPath)); // 宽高 final int w = (int) Math .sqrt(Math.abs(point1X - point2X) * Math.abs(point1X - point2X) + Math.abs(point1Y - point2Y) * Math.abs(point1Y - point2Y)) + 12 * (7 - 1); final int h = w; Hashtable hints2 = new Hashtable(); hints2.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); hints2.put(EncodeHintType.CHARACTER_SET, "UTF-8"); hints2.put(EncodeHintType.MARGIN, 1); Graphics2D graphics = readImage.createGraphics(); //此处,偏移,会有定位问题 int x = Math.round(point1X) - 36; int y = Math.round(point2Y) - 36; // 开始合并绘制图片 graphics.drawImage(writeFile, x, y, w, h, null); // logo边框大小 graphics.setStroke(new BasicStroke(2)); // //logo边框颜色 graphics.setColor(Color.WHITE); graphics.drawRect(x, y, w, h); readImage.flush(); graphics.dispose(); // 打印替换后的图片 NewImageUtils.generateWaterFile(readImage, "F:\\image\\save.jpg"); } catch (IOException e) { log.error("资源读取失败" + e.getMessage()); e.printStackTrace(); } catch (NotFoundException e) { log.error("读取图片二维码坐标前发生异常:" + e.getMessage()); e.printStackTrace(); } } public static void main(String[] args) { deEncodeByPath("F:\\image\\zfb.jpg", "F:\\image\\gzh.jpg"); } } 原文链接:https://blog.csdn.net/u012891290/article/details/86582687
-
Zxing是Google提供的关于条码(一维码、二维码)的解析工具,提供了二维码的生成与解析的方法,现在我简单介绍一下使用Java利用Zxing生成与解析二维码1、二维码的生成 1.1 将Zxing-core.jar 包加入到classpath下。 1.2 二维码的生成需要借助MatrixToImageWriter类,该类是由Google提供的,可以将该类拷贝到源码中,这里我将该类的源码贴上,可以直接使用。import com.google.zxing.common.BitMatrix; import javax.imageio.ImageIO; import java.io.File; import java.io.OutputStream; import java.io.IOException; import java.awt.image.BufferedImage; public final class MatrixToImageWriter { private static final int BLACK = 0xFF000000; private static final int WHITE = 0xFFFFFFFF; private MatrixToImageWriter() {} public static BufferedImage toBufferedImage(BitMatrix matrix) { int width = matrix.getWidth(); int height = matrix.getHeight(); BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE); } } return image; } public static void writeToFile(BitMatrix matrix, String format, File file) throws IOException { BufferedImage image = toBufferedImage(matrix); if (!ImageIO.write(image, format, file)) { throw new IOException("Could not write an image of format " + format + " to " + file); } } public static void writeToStream(BitMatrix matrix, String format, OutputStream stream) throws IOException { BufferedImage image = toBufferedImage(matrix); if (!ImageIO.write(image, format, stream)) { throw new IOException("Could not write an image of format " + format); } } }1.3 编写生成二维码的实现代码try { String content = "120605181003;http://www.cnblogs.com/jtmjx"; String path = "C:/Users/Administrator/Desktop/testImage"; MultiFormatWriter multiFormatWriter = new MultiFormatWriter(); Map hints = new HashMap(); hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, 400, 400,hints); File file1 = new File(path,"餐巾纸.jpg"); MatrixToImageWriter.writeToFile(bitMatrix, "jpg", file1); } catch (Exception e) { e.printStackTrace(); } 现在运行后即可生成一张二维码图片,是不是很简单啊? 接下来我们看看如何解析二维码2、二维码的解析 2.1 将Zxing-core.jar 包加入到classpath下。 2.2 和生成一样,我们需要一个辅助类( BufferedImageLuminanceSource),同样该类Google也提供了,这里我同样将该类的源码贴出来,可以直接拷贝使用个,省去查找的麻烦BufferedImageLuminanceSource import com.google.zxing.LuminanceSource; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; public final class BufferedImageLuminanceSource extends LuminanceSource { private final BufferedImage image; private final int left; private final int top; public BufferedImageLuminanceSource(BufferedImage image) { this(image, 0, 0, image.getWidth(), image.getHeight()); } public BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height) { super(width, height); int sourceWidth = image.getWidth(); int sourceHeight = image.getHeight(); if (left + width > sourceWidth || top + height > sourceHeight) { throw new IllegalArgumentException("Crop rectangle does not fit within image data."); } for (int y = top; y < top + height; y++) { for (int x = left; x < left + width; x++) { if ((image.getRGB(x, y) & 0xFF000000) == 0) { image.setRGB(x, y, 0xFFFFFFFF); // = white } } } this.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY); this.image.getGraphics().drawImage(image, 0, 0, null); this.left = left; this.top = top; } @Override public byte[] getRow(int y, byte[] row) { if (y < 0 || y >= getHeight()) { throw new IllegalArgumentException("Requested row is outside the image: " + y); } int width = getWidth(); if (row == null || row.length < width) { row = new byte[width]; } image.getRaster().getDataElements(left, top + y, width, 1, row); return row; } @Override public byte[] getMatrix() { int width = getWidth(); int height = getHeight(); int area = width * height; byte[] matrix = new byte[area]; image.getRaster().getDataElements(left, top, width, height, matrix); return matrix; } @Override public boolean isCropSupported() { return true; } @Override public LuminanceSource crop(int left, int top, int width, int height) { return new BufferedImageLuminanceSource(image, this.left + left, this.top + top, width, height); } @Override public boolean isRotateSupported() { return true; } @Override public LuminanceSource rotateCounterClockwise() { int sourceWidth = image.getWidth(); int sourceHeight = image.getHeight(); AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth); BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE_BYTE_GRAY); Graphics2D g = rotatedImage.createGraphics(); g.drawImage(image, transform, null); g.dispose(); int width = getWidth(); return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width), getHeight(), width); } } 2.3 编写解析二维码的实现代码 try { MultiFormatReader formatReader = new MultiFormatReader(); String filePath = "C:/Users/Administrator/Desktop/testImage/test.jpg"; File file = new File(filePath); BufferedImage image = ImageIO.read(file);; LuminanceSource source = new BufferedImageLuminanceSource(image); Binarizer binarizer = new HybridBinarizer(source); BinaryBitmap binaryBitmap = new BinaryBitmap(binarizer); Map hints = new HashMap(); hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); Result result = formatReader.decode(binaryBitmap,hints); System.out.println("result = "+ result.toString()); System.out.println("resultFormat = "+ result.getBarcodeFormat()); System.out.println("resultText = "+ result.getText()); } catch (Exception e) { e.printStackTrace(); } 现在运行后可以看到控制台打印出了二维码的内容。 到此为止,利用Zxing生成和解析二维码就讲述演示完毕,主要为自己做备忘,同时方便有需要的人。原文链接:https://www.cnblogs.com/jtmjx/archive/2012/06/18/2545209.html
-
ColorConvertOp java.awt.image包下面有个类java.awt.image.ColorConvertOp,类名直译就是”颜色转换操作”。 顾名思义,它的作用就是将一个色彩空间(color space)的图像转换为另一个色彩空间的图像。有了这个神器我们就能轻易的将一张彩色图你像转换成灰度(gray)或其他色彩空间图像。 代码非常简单,只要一行。 public BufferedImage toGray(BufferedImage srcImg){ return new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null).filter(srcImg, null); } 依此类推,你可以参照ColorConvertOp的参数说明将图像转为其他格式。 java.awt.color.ColorSpace中列出了很多支持的色彩空间定义TYPE_RGB,TYPE_CMYK,TYPE_HSV,TYPE_YCbCr…. Raster.getDataElements 有时我们通过ImageIO得到解码后的图像数据对象(BufferedImage)以后,需要获取图像矩阵的裸数据(即一个存储图像数据的byte数组)。 BufferedImage中提供了一个getRGB()方法,它返回的是一个ARGB格式int[]数组(每个int型元素的4个字节分别代表一个像素的Alpha,Red,Green,Blue四个通道) 如果你要从这个方法获取RGB的数组,你还得自己写转换代码: /** * 返回图像的RGB格式字节数组 * @param image * @return */ public static byte[] getMatrixRGB(BufferedImage image){ int w = image.getWidth(); int h = image.getHeight(); int[] intArray = new int[w * h]; byte[] matrixRGB = new byte[w * h * 3]; image.getRGB(0, 0, w, h, intArray, 0, w); // ARGB->RGB for(int i=0,b=0;i matrixRGB[b++]=(byte) (matrixRGB[i]&0x000000FF); matrixRGB[b++]=(byte) ((matrixRGB[i]&0x0000FF00)>>8); matrixRGB[b++]=(byte) ((matrixRGB[i]&0x00FF0000)>>16); } return matrixRGB; } 好烦呐,我以前就是这么干的,真的没有提供更好的方法吗? 不是没有更好的方法,而是我学艺不精没找到而已。 在仔细研究了BufferedImage的代码之后,才明白getRGB()只是BufferedImage为默认 RGB 颜色模型 (TYPE_INT_ARGB)提供的一个便利性封装。 通过getRGB()源码可以知道BufferedImage对象中真正的图像数据是由成员对象raster(java.awt.image.WritableRaster)管理。而WritableRaster是java.awt.image.Raster的子类。Raster中getDataElements方法可以我们所需要的字节数组。 还以前面图像转灰度举例,如果要从灰度图像中获取图像矩阵的字节数组,代码示例如下: /** * 获取灰度图像的字节数组 * @param image * @return */ public static byte[] getMatrixGray(BufferedImage image) { // 转灰度图像 BufferedImage grayImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY); new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null).filter(image, grayImage); // getData方法返回BufferedImage的raster成员对象 return (byte[]) grayImage.getData().getDataElements(0, 0, image.getWidth(), image.getHeight(), null); } 注意这里return语句使用了(byte[])强制类型转换,因为getDataElements返回的是打开声明 java.lang.Object对象。 也就是说getDataElements返回的未必是byte[]类型,为什么呢?看下面getDataElements方法的说明: 看不懂没关系,我们可以看到这里的返回的类型可能是:TYPE_BYTE,TYPE_USHORT,TYPE_INT,TYPE_SHORT,TYPE_FLOAT,TYPE_DOUBLE。并不一定是byte。 那么问题来了,如何控制返回的数组类型是byte[]呢? 同样,我们可以使用前面的ColorConvertOp对象进行转换。 比如我们需要得到图像的RGB数据: /** * 获取图像RGB格式数据 * @param image * @return */ public static byte[] getMatrixRGB(BufferedImage image){ if(image.getType()!=BufferedImage.TYPE_3BYTE_BGR){ // 转sRGB格式 BufferedImage rgbImage = new BufferedImage( image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR); new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null).filter(image, rgbImage); // 从Raster对象中获取字节数组 return (byte[]) rgbImage.getData().getDataElements(0, 0, rgbImage.getWidth(), rgbImage.getHeight(), null); }else{ return (byte[]) image.getData().getDataElements(0, 0, image.getWidth(), image.getHeight(), null); } } 原文链接:https://blog.csdn.net/10km/article/details/51866321
-
我们在开发Java项目的时候或多或少都会跟Java环境打交道,如何按照需求更改我们的环境配置达到我们所需要的环境呢?本文中将对这些进行简单的探究。1.系统属性的简介系统属性就是系统级全局变量,该参数在程序中任何位置都可以访问到。优先级是最高的,该参数的使用会覆盖程序中的同名配置(相当霸道)。设置系统属性的标准格式为:-Dargname=argvalue,如果有多个参数的话它们之间需要使用空格来进行分隔,如果参数值中间存在空格,则需要使用引号来将其括起来。 其中的参数名可以是 Java 默认的这样这些参数就可以由 JVM 虚拟机来自动识别并且生效了。举个栗子: -Dfile.encoding=UTF-8 是用于指定文件编码格式,也可以是自定义的参数,另外个栗子:-Dtest=123,设置完后程序中是可以读取到该参数值的并且执行相关的逻辑操作。那么虚拟机是可以识别了,那么我们如何来进行获取呢,我们获取虚拟机中系统参数设置的参数键值对,可以在程序中使用System.getProperty("propertyName") 方法来进行获取对应的参数值,并且可以在程序中通过System.setProperty(k,v)方法来设置系统参数,其中参数-X/-XX 为非标准系统参数形式,一般与 JVM 虚拟机设置有关,参数名和值都由JVM 规范来规定。比如:-Xms :初始堆大小、-Xmx :最大堆大小。常用的方法中System.getProperty(XXX)是用来获取系统属性的,而System.getEnv(XXX)方法则是用来获取系统环境变量的。比如可以再IDEA中的Configuration中VM options设置-Dtest.aaa=123,然后再在项目中使用System.getProperty("test.aaa")就可以获取到123这个值了。2 运行参数main方法中执行时传入的参数值,如果参数有多个是通过空格来进行分隔的。main 方法的一般格式是:public static void main(String[] args),其中,Stringp[] args 就是存储运行参数的变量,在程序中可以直接使用。
-
1.MyBatis-Plus简介MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。在开发过程中,MyBatis-Plus给我们带来了很多的遍历,一些简单逻辑的sql操作可以不用再写sql通过简单的一两行代码就可以完成。2.MyBatis-Plus的使用MyBatis-Plus在开发过程中的使用常常跟lombok一起使用,通过lombok来简化实体类的创建。然后通过创建自己的IBaseService 继承Mybatis-Plus提供的基类,最后用自己创建的service对象调用,就可以便捷的调用MyBatis-Plus中封装好的各种实用的CRUD方法了(插入、更新、删除、根据id插入、根据id更新、根据id删除、批量处理数据等),我们还可以传入创建的Wrapper对象来添加各种筛选条件。@Datapublic class User { private Long id; private String name; private Integer age;}...// 插入boolean save(T entity);// 批量插入boolean saveBatch(Collection entityList);// 批量插入,每次插入数量boolean saveBatch(Collection entityList, int batchSize);...// 更新或插入boolean saveOrUpdate(T entity);...// 根据UpdateWrapper条件更新boolean update(Wrapper updateWrapper);// 根据ID更新boolean updateById(T entity);// 根据ID批量更新boolean updateBatchById(Collection entityList);3.MyBatis-Plus存在的小问题在Mybatis-Plus中调用updateById方法进行数据更新默认情况下是不能更新空值字段的,而在实际开发过程中,经常会遇到需要将字段值更新为空值的情况。那么我们应该怎么去改进呢?因为Mybatis-Plus中字段的更新策略是通过FieldStrategy属性控制的,它是在实体字段上,如果不通过@TableField注解指定字段的更新策略,字段默认的更新策略就是FieldStrategy.DEFAULT,即跟随全局策略。 而Mybatis-Plus的全局配置里字段的默认更新策略是FieldStrategy.NOT_NULL是进行空值判断的,不会对NULL值数据进行处理的。 知道了问题那么我们就可以通过问题去探索解决方案了,我们可以设置字段级别的更新策略为IGNORED就可以了,只需要在实体中字段上面通过@TableField注解指定字段的更新策略为FieldStrategy.IGNORED,忽略空值判断直接进行更新就可以了。@TableField(updateStrategy = FieldStrategy.IGNORED) private String name;还可以设置全局更新策略的IGNORED ,通过修改Mybatis-Plus的项目级别的全局更新策略来进行控制, 在spring boot中只需要修改属性: mybatis-plus.global-config.db-config.update-strategy=ignored就可以完成策略的变更。以上就是Mybatis-Plus中小知识点的总结。
-
这个添加组织的接口,调了也没添加上去,然后也不报错,返回的结果是查询所有组织的接口的返回值
-
@Test public void testNQueen() { int n = 14; int limit = n == 32 ? -1 : (1 << n) - 1; System.out.println(binaryNQueen(limit, 0, 0, 0)); } /** * n皇后问题 二进制解法 * @param limit 皇后规模 * @param cloLimit 列限制 * @param lLimit 左斜线限制 * @param rLimit 右斜线限制 * @return */ public int binaryNQueen(int limit, int cloLimit, int lLimit, int rLimit) { if (cloLimit == limit) { return 1; } int tempLimit = ~(cloLimit | lLimit | rLimit) & limit; int temp; int res = 0; while (tempLimit != 0) { temp = tempLimit & (~tempLimit + 1); tempLimit = tempLimit - temp; res += binaryNQueen(limit, cloLimit | temp, (lLimit | temp) << 1, (rLimit | temp) >>> 1); } return res; }
匿名用户
发表于2022-09-26 14:49:27
2022-09-26 14:49:27
最后回复
匿名用户
2022-09-26 14:49:27
69 0 -
1.springbootspringboot框架目前是最常用的Java Web项目快速开发框架,我们的技术选型也常常围绕着springboot来进行搭配搭建,而我们在搭建的过程中需要在.properties或者.yml配置文件中进行一些简单的属性配置,本文中就是对这些配置进行归纳总结。2.应用相关的配置配置服务器HTTP端口可以应用server.port = 端口号用于Server响应头的值(如果为空,则不发送头)可以应用server.server-header =是否应将X-Forwarded- *头应用于HttpRequest可以应用server.use-forward-headers =Servlet context init参数可以应用server.servlet.context-parameters .*=应用程序的上下文路径可以应用server.servlet.context-path =主调度程序servlet的路径可以应用server.servlet.path = /会话cookie的最大有效时间,如果未指定持续时间后缀,则将使用秒可以应用server.servlet.session.cookie.max-age =会话超时。如果未指定持续时间后缀,则将使用秒可以应用server.servlet.session.timeout =连接器在关闭连接之前等待另一个HTTP请求的时间,未设置时默认使用连接器的默认值。使用值-1表示没有(即无限)超时可以应用server.connection-timeout =错误控制器的路径可以应用server.error.path = /error3.log4j2日志相关配置日志配置文件的位置logging.config =记录异常时使用的转换字logging.exception-conversion-word =xxx 。日志文件名logging.file = 要保留的归档日志文件的最大值logging.file.max-history = 0最大日志文件大小logging.file.max-size = 100MB日志级别严重性映射logging.level.* = DEBUG日志文件的位置logging.path = 用于输出到控制台的Appender模式logging.pattern.console =以上是Springboot 2.0版本使用的相关配置属性,下面我们介绍下Spring2.2版本使用的一些配置变更。4.Springboot 2.2配置变更Springboot 2.2有很多的变更主要的性能提升在:绑定大量配置属性所需的时间已大大减少;当Spring Boot PersistenceUnit通过扫描JPA实体完全准备一个时,由于它是冗余的,因此Hibernate自己的实体扫描已被禁用;自动配置中的注入点已经过改进,仅适用于必须创建bean的情况;现在仅在启用和公开端点的情况下(通过JMX或HTTP)创建与Actuator端点相关的Bean; 编解码器自动配置的条件已得到改善,以便在不再使用编解码器时不再对其进行配置;Tomcat的MBean注册表默认情况下处于禁用状态,从而将Tomcat的内存占用量减少了大约2MB等 配置文件的变更有:将logging.file属性变更为logging.file.name将logging.path属性变更为logging.file.pathserver.connection-timeout不再建议使用该属性了 将server.use-forward-headers=true属性变更为server.forward-headers-strategy=native将agentMaven属性变更为agents将WebTestClientBuilderCustomizer移动到org.springframework.boot.test.web.reactive.server
-
线程常用操作线程的命名和取得线程的命名和取得都是来源于Thread类中线程名称的操作常用有一下三种操作构造方法命名:public Thread(Runnalbe target,String name) ;setName()方法命名:public final void setName(String name);getName()方法取得名字:public final String getName();范例:在run()方法中获取线程名称class mythread implements Runable{ @Override public void run{ System.out.println(Thrad.currentThread().getName()); } } public class ThreadDemo{ public static void main(String[] args) throws Exception{ mythread mt=new mythread(); new Thread(mt,"线程A").start();//设置了线程名字 new Thread(mt).start();//未设置线程名字 new Thread(mt,"线程B").start();//设置了线程名字 } }获取线程名称时,未命名线程会自动分配名称 接下来获取主线程名称class mythread implements Runable{ @Override public void run{ System.out.println(Thrad.currentThread().getName()); } } public class ThreadDemo{ public static void main(String[] args) throAws Exception{ mythread mt=new mythread(); new Thread(mt,"线程对象").start();//设置了线程名字 mt.run();//对象直接调用run()方法 } }==获取主线程名称为main(主方法也是线程)==线程休眠我们可以希望某个线程能够暂缓执行以方便观察运行状态在进行休眠的时候有可能会产生在进行休眠的时候有可能会产生 中断异常“InterruptedException”,中断异常属于Exception的子类,证明该异常必须进行处理==休眠方法:==休眠:public static void sleep(long millis) throws InterruptedException;休眠:public static void sleep(long mills,int nanos) throws InterruptedException;范例:观察休眠处理(单个对象进行线程休眠处理)public class ThreadDemo{ public static void main(String[] args) throws Exception{ new Thread(()->{ for(int x=0;x<10;x++) { System.out.println(Thread.currentThrad().getName()+",x="+x); try{ Thread.sleep(1000);暂缓执行 } catch(InterruptedException e){ e.printStackTrace(); } } },"线程对象").start(); } }在线程的启动上有线程后,当程序休眠再启动也有先后,就像接力比赛,接棒时当作休眠,休眠后每个人的运行速度是不相同的,这就造成了线程执行完毕的先后顺序也是不同的范例:产生多个线程对象进行线程处理public class ThreadDemo{ public static void main(String[] args) throws Exception{ Runnable run=()->{ for(int x=0;x<10;x++) { System.out.println(Thread.currentThrad().getName()+",x="+x); try{ Thread.sleep(1000);暂缓执行 } catch(InterruptedException e){ e.printStackTrace(); } } }; for(int num=0;num<5;num++) { new Thread(run,"执行线程"+num).start(); } } }线程休眠要通过运行代码自己观察线程中断在之前的线程休眠中发现里面提供有一个中断异常,这实际上证明线程休眠是可以被打断的,这种打断肯定是由其他线程完成的在Thread类里面提供有线程处理方法判断线程是否被中断:public boolean isInterrupted();中断线程执行:public void interrupt();范例:观察线程的中断处理public class ThreadDemo { public static void main(String[] args) throws Exception { Thread thread=new Thread(()->{ System.out.println("*****我需要休眠*****"); try { Thread.sleep(10000);//休息10秒 System.out.println("***睡足了,可以去工作了***"); } catch (InterruptedException e) { // TODO Auto-generated catch block System.out.println("休息被打断"); } }); thread.start();//开始休息 Thread.sleep(1000);//先休息1秒钟 if(!thread.isInterrupted()) {//询问是否中断休息 //没有中断 thread.interrupt();//现在打断你的休息 } } }正在执行的线程都是可以被中断的,中断的线程必须进行异常处理线程强制运行当满足某些条件之后,某一个线程对象可以一直独占资源一直到线程结束范例:观察一个没有强制执行的程序public class ThreadDemo { public static void main(String[] args) throws Exception { Thread thread=new Thread(()->{ for(int x=0;x<100;x++) { try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"执行、x="+x); } },"玩耍的线程"); thread.start(); for(int x=0;x<100;x++) { Thread.sleep(100); System.out.println("霸道的main线程执行x="+x); } } }我们发现在子线程会和主线程抢占资源进行输出,接下来我们看看在利用了线程的强制执行后的运行状态在Thread类里面提供有强制执行方法,join()方法==public final void join() throws InterruptedException==利用join()方法我们可以使线程强制执行独占资源从强制执行抛出异常看出,强制执行也可以被中断范例:强制执行程序public class ThreadDemo { public static void main(String[] args) throws Exception { Thread mainThread=new Thread().currentThread();//获取主线程 Thread thread=new Thread(()->{ for(int x=0;x<100;x++) { try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(x>3) { try { mainThread.join();//霸道的线程开始执行 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+"执行、x="+x); } },"玩耍的线程"); thread.start(); for(int x=0;x<100;x++) { Thread.sleep(100); System.out.println("霸道的main线程执行x="+x); } } }可以看出当下x>3后main()开始独占资源,当main()执行完成后其他线程才开始执行在进行强制执行的时候一定要获取强制执行线程对象才可以进行join的操作线程礼让在多线程中,可以先将资源让出去让别的线程先执行,线程的礼让可以用Thread中的方法礼让方法:public static void yield();范例:线程的礼让执行public class ThreadDemo { public static void main(String[] args) throws Exception { Thread thread=new Thread(()->{ for(int x=0;x<100;x++) { if(x%3==0) { Thread.yield();//玩耍的线程礼让了 System.out.println("****玩耍的线程礼让了*****"); } try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"执行、x="+x); } },"玩耍的线程"); thread.start(); for(int x=0;x<100;x++) { Thread.sleep(100); System.out.println("霸道的main线程执行x="+x); } } }每一次调用yield()都只会礼让一次当前的资源线程优先级从理论上讲线程的优先级越高越有可能先执行(越有可能先抢占到资源)在Thread类里面提供有如下的两个处理方法设置优先级:public final void setPriority(int newPriority);获取优先级:public final int getPriority(); 在进行优先级定义的时候都是通过int型的数字来进行完成的,而对于此类数字的选择在Thread类里面就有定义最高优先级:public static final int MAX_PRIORITY、10(优先级的值)中等优先级:public static final int NORM_PRIORITY、5(优先级的值)最低优先级:public static final int MIN_PRIORITY、1(优先级的值)范例:没有设置优先级public class ThreadDemo { public static void main(String[] args) throws Exception { Runnable run=()->{ for(int x=0;x<10;x++) { try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"执行"); } }; Thread threadA=new Thread(run,"线程A对象"); Thread threadB=new Thread(run,"线程B对象"); Thread threadC=new Thread(run,"线程C对象"); threadA.start(); threadB.start(); threadC.start(); } }不同电脑效果不同,本人的是B优先执行 接下来看使用优先级后电脑执行的效果 范例:观察设置优先级后的效果public class ThreadDemo { public static void main(String[] args) throws Exception { Runnable run=()->{ for(int x=0;x<10;x++) { try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"执行"); } }; Thread threadA=new Thread(run,"线程A对象"); Thread threadB=new Thread(run,"线程B对象"); Thread threadC=new Thread(run,"线程C对象"); threadA.setPriority(Thread.MIN_PRIORITY);//把AB设置优先级最小 threadB.setPriority(Thread.MIN_PRIORITY);//把AB设置优先级最小 threadC.setPriority(Thread.MAX_PRIORITY);//把AB设置优先级最小 threadA.start(); threadB.start(); threadC.start(); } }提高有先级确实可以提高线程先执行的可能,但是并不是绝对先执行补充:主方法是一个主线程,主线程的优先级是多少呢?public class ThreadDemo { public static void main(String[] args) throws Exception { System.out.println(Thread.currentThread().getPriority()); } }发现主线程的优先级是5,只是中等优先级,同时这与我们默认的方法的优先级是相同的
-
1.时间类型的转换问题时间类型的转换问题一直是我们开发中经常接触的一个问题,涉及到的问题有字符串转时间,时间转字符串等等,经常用,又总是记不太清,本文中对这些时间类型的相关转换进行记录和总结。2.字符串和Date类型互相转换2.1 利用SimpleDateFormat转换通过java.text.SimpleDateFormat类进行转换,这个类中有许多专门用来实现时间和字符串之间的互相转换的方法。首先需要创建格式化的对象,并且设置需要格式化的样式,比如可以用"yyyy-MM-dd HH:mm:ss","yyyy/MM/dd HH:mm:ss","yyyy年MM月dd日 HH时mm分ss秒"等等这种全部动态变化的格式,也可以指定一部分动态换行一部分不变的样式,比如可以用“yyyy-MM-dd 10:00:00”,"2022-MM-dd HH:mm:ss"等等格式。SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");2.1.1 时间对象转字符串: 通过sdf.format(需要转换的时间对象); 格式化方法,可以将日期对象转换为我们需要的时间格式的字符串形式,返回的时间字符串的格式是由上面创建对象时定义格式来决定的。2.1.2 时间字符串转日期对象: 首先需要保证字符串的格式也和上面我们创建的格式化对象sdf实例中定义的格式一样, 然后通过sdf.parse("需要转换的时间字符串");方法,就可以将时间字符串转换成时间对象了。2.2 利用DateUtil转换还可以通过import cn.hutool.core.date.DateUtil类中的专门转换时间的方法进行转换。2.2.1 时间对象转时间字符串通过String time = DateUtil.format(new Date(),"yyyyMMddHHmmss");方法可以将时间对象转换为指定格式的时间格式的字符串,第二个参数就是需要转换的时间格式。2.2.2 时间字符串转时间对象通过Date time = DateUtil.parse(待转化的时间格式字符串, "yyyyMMddHHmmss");方法以将时间形式的字符串转换为指定格式的时间格式的对象,第二个参数就是需要转换的时间格式,需要注意的是待转化的字符串的格式需要跟第二个参数的时间格式保持一致。2.2.3 增加时间和减少时间可以通过Date 减少后的时间 = DateUtil.offsetMinute(time, -时间);方法将时间对象传入第一个参数,将负整数类型传入第二个参数,表示减少多少分钟。Date 增加后的世界 = DateUtil.offsetMinute(time, 时间);方法将时间对象传入第一个参数,将正整数类型传入第二个参数,表示增加多少分钟。类似的还有增加减少秒.offsetSecond(),增加减少小时offsetHour(),增加减少天.offsetDay(),增加减少月offsetMonth(),增加减少年.offsetfYear(),都可以利用这个类中的方法便捷的进行增减操作。以上就是对时间转换小知识点简单归纳和总结。
-
1.IDEA简介IDEA全称是IntelliJ IDEA,它是JetBrains公司推出一款集成开发工具,在Java开发工具中的由于其集成了很多应用插件,比如提交代码的Git,依赖管理的Maven,项目启动用到的Tomcat等等,就是因为相对于其它开发工具来说IDEA提供了这些非常强大的黑科技,所以尽管有各种各样的开发工具,开发者们还是越来越受开发者的青睐这款可以非常便捷的开发我们的Java相关项目的开发工具。2.IDEA存在的问题成也萧何败也萧何,也正是因为IDEA集成了各式各样的插件以及各种便捷开发的功能,使得我们的开发变得更加轻松和舒适,也造成了IDEA会占用很多内存,有种很笨重的感觉,并且由于服务多了往往会有一些照顾不到的地方,我们在使用的过程中往往会碰到各种各样奇怪的问题出现,下面本文中主要总结一下修改的修改代码重启不生效的解决方法。3.IDEA使用中的修改的修改代码重启不生效的解决方法问题描述:明明修改了代码,但是重启后修改的代码却灵异的失效了,代码看着好的,就是不起作用,感觉就像是有缓存一样,面对这个问题应该如何去解决呢?可以通过maven clean清理项目后再重新打包项目来解决,但是这样就感觉很麻烦,并且如果忘记清理后再打包,代码还是会没有生效,也很难排查到,会造成很多不必要的麻烦。我们可以通过如下方法进行尝试解决,毕竟个人的环境和配置不同,有些在一台机器上生效了,在另一台又不行了,所以多准备几个解决方法有备无患,解决方法如下:方法1:右上角-Edit Configurations中,设置Update选项为Update classes and resources,如果不行继续进行下个方法;方法2:Ctrl+Shift+Alt+/ 四建齐按弹出框选择Registry,选中打勾 “compiler.automake.allow.when.app.running” 。方法3 在左上角“File”--> “Settings”--> “Build,Execution,Deplyment”--> “Compiler”中勾选中 “Build project automatically” 。方法4:删除项目的.idea文件,关闭IDEA后再重新打开IDEA后生效。以上就是IDEA使用中出现修改代码不生效的小技巧的归纳总结。
上滑加载中
推荐直播
-
华为云码道Agent集成与鸿蒙实战2026/08/11 周二 19:00-21:00
王一男-华为云码道产品规划专家;李炎-华为云码道产品专家;彭江敏-华为云鸿蒙端云一体化开发专家
本次直播带你解读华为云码道7月份产品新特性、新功能。更有专家演示码道Agent Space × 钉钉机器集成实战,从0到1打通消息通道;码道鸿蒙端云一体化实战,快速搭建员工签到系统。
回顾中 -
华为云开发者AI素养直播课·第五期2026/09/04 周五 16:00-18:00
林华鼎-华为云AI开发者运营负责人;蒋春阳-华为云AI开发者案例开发专家
本期直播内容: AI工具体验营 · 第5-8课连讲。Agent-Team 多智能体协作完成毕业设计实践
回顾中 -
华为云开发者AI素养ClassRoom·第六期2026/09/08 周二 19:00-20:00
樊渊-2026华为软件挑战赛冠军
高手来了:看软挑高手解析二维排样问题—从工业难题到算法突破
回顾中
热门标签