格式化
This commit is contained in:
parent
c950e1b041
commit
e6dd15a9e7
6
pom.xml
6
pom.xml
|
@ -57,6 +57,12 @@
|
||||||
<version>1.6.2</version>
|
<version>1.6.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- websocket -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -21,10 +21,11 @@ public class LoginController {
|
||||||
CodeCheck codeCheck;
|
CodeCheck codeCheck;
|
||||||
@Resource
|
@Resource
|
||||||
MailUtil mailUtil;
|
MailUtil mailUtil;
|
||||||
|
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public Result Login(@RequestBody User user) throws IOException {
|
public Result Login(@RequestBody User user) throws IOException {
|
||||||
Result result = new Result();
|
Result result = new Result();
|
||||||
if (login.LoginCheck(user)!=null) {
|
if (login.LoginCheck(user) != null) {
|
||||||
|
|
||||||
result.setStatus(200);
|
result.setStatus(200);
|
||||||
result.setResponseStr(login.LoginCheck(user));
|
result.setResponseStr(login.LoginCheck(user));
|
||||||
|
@ -39,7 +40,7 @@ public class LoginController {
|
||||||
@PostMapping("/register")
|
@PostMapping("/register")
|
||||||
public Result Register(@RequestBody User user) throws IOException {
|
public Result Register(@RequestBody User user) throws IOException {
|
||||||
System.out.println("被调用了");
|
System.out.println("被调用了");
|
||||||
System.out.println("user是啥"+user);
|
System.out.println("user是啥" + user);
|
||||||
Result result = new Result();
|
Result result = new Result();
|
||||||
result.setStatus(login.Register(user));
|
result.setStatus(login.Register(user));
|
||||||
return result;
|
return result;
|
||||||
|
@ -48,10 +49,11 @@ public class LoginController {
|
||||||
@PostMapping("/checkCode")
|
@PostMapping("/checkCode")
|
||||||
public boolean checkCode(@RequestBody Email email) {
|
public boolean checkCode(@RequestBody Email email) {
|
||||||
System.out.println(email);
|
System.out.println(email);
|
||||||
return codeCheck.CheckCode(email.getEmail(),email.getCode());
|
return codeCheck.CheckCode(email.getEmail(), email.getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/sendCode")
|
@PostMapping("/sendCode")
|
||||||
public void sendCode(@RequestBody Email email){
|
public void sendCode(@RequestBody Email email) {
|
||||||
System.out.println(email.getEmail());
|
System.out.println(email.getEmail());
|
||||||
mailUtil.sendMail(email.getEmail());
|
mailUtil.sendMail(email.getEmail());
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,8 @@ public class Login implements UserTable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addUser(User user) throws IOException {
|
public void addUser(User user) throws IOException {
|
||||||
SqlSession sqlSession=MybatisSingleton.getSqlSessionFactory().openSession();
|
SqlSession sqlSession = MybatisSingleton.getSqlSessionFactory().openSession();
|
||||||
sqlSession.insert("dao.Login.addUser",user);
|
sqlSession.insert("dao.Login.addUser", user);
|
||||||
sqlSession.commit();
|
sqlSession.commit();
|
||||||
sqlSession.close();
|
sqlSession.close();
|
||||||
}
|
}
|
||||||
|
@ -25,22 +25,22 @@ public class Login implements UserTable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateUser(User oldUser,User newUser) {
|
public void updateUser(User oldUser, User newUser) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public User getUser(User user) throws IOException {
|
public User getUser(User user) throws IOException {
|
||||||
SqlSession sqlSession= MybatisSingleton.getSqlSessionFactory().openSession();
|
SqlSession sqlSession = MybatisSingleton.getSqlSessionFactory().openSession();
|
||||||
User returnUser=sqlSession.selectOne("dao.Login.getUser",user);
|
User returnUser = sqlSession.selectOne("dao.Login.getUser", user);
|
||||||
sqlSession.close();
|
sqlSession.close();
|
||||||
return returnUser;
|
return returnUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public User emailCheck(User user) throws IOException {
|
public User emailCheck(User user) throws IOException {
|
||||||
SqlSession sqlSession=MybatisSingleton.getSqlSessionFactory().openSession();
|
SqlSession sqlSession = MybatisSingleton.getSqlSessionFactory().openSession();
|
||||||
User returnUser=sqlSession.selectOne("dao.Login.emailCheck",user);
|
User returnUser = sqlSession.selectOne("dao.Login.emailCheck", user);
|
||||||
sqlSession.close();
|
sqlSession.close();
|
||||||
return returnUser;
|
return returnUser;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,17 +5,19 @@ import com.example.chat.entity.User;
|
||||||
import org.apache.ibatis.session.SqlSession;
|
import org.apache.ibatis.session.SqlSession;
|
||||||
import org.springframework.boot.CommandLineRunner;
|
import org.springframework.boot.CommandLineRunner;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class Test01 implements CommandLineRunner {
|
public class Test01 implements CommandLineRunner {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(String... args) throws Exception {
|
public void run(String... args) throws Exception {
|
||||||
while (true){
|
while (true) {
|
||||||
SqlSession sqlSession= MybatisSingleton.getSqlSessionFactory().openSession();
|
SqlSession sqlSession = MybatisSingleton.getSqlSessionFactory().openSession();
|
||||||
User user=sqlSession.selectOne("dao.Login.getUser","123");
|
User user = sqlSession.selectOne("dao.Login.getUser", "123");
|
||||||
if (user!=null){
|
if (user != null) {
|
||||||
System.out.println(user);
|
System.out.println(user);
|
||||||
}
|
}
|
||||||
sqlSession.close();
|
sqlSession.close();
|
||||||
|
|
|
@ -9,12 +9,13 @@ import java.io.IOException;
|
||||||
public class MybatisSingleton {
|
public class MybatisSingleton {
|
||||||
private static SqlSessionFactory sqlSessionFactory;
|
private static SqlSessionFactory sqlSessionFactory;
|
||||||
|
|
||||||
private MybatisSingleton(){
|
private MybatisSingleton() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SqlSessionFactory getSqlSessionFactory() throws IOException {
|
public static SqlSessionFactory getSqlSessionFactory() throws IOException {
|
||||||
if(sqlSessionFactory==null){
|
if (sqlSessionFactory == null) {
|
||||||
sqlSessionFactory=new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis.xml"));
|
sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis.xml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return sqlSessionFactory;
|
return sqlSessionFactory;
|
||||||
|
|
|
@ -19,10 +19,12 @@ public class CodeRedis implements RedisUtil {
|
||||||
valueOperations.set(account, code, 60, TimeUnit.SECONDS);
|
valueOperations.set(account, code, 60, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getRedis(String account) {
|
public String getRedis(String account) {
|
||||||
return stringRedisTemplate.opsForValue().get(account);
|
return stringRedisTemplate.opsForValue().get(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void delRedis(String account) {
|
public void delRedis(String account) {
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,10 @@ import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface RedisUtil {
|
public interface RedisUtil {
|
||||||
public abstract void addRedis(String key,String value);
|
public abstract void addRedis(String key, String value);
|
||||||
|
|
||||||
public abstract void delRedis(String key);
|
public abstract void delRedis(String key);
|
||||||
|
|
||||||
public abstract String getRedis(String key);
|
public abstract String getRedis(String key);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,15 @@ import javax.annotation.Resource;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public class TokenRedis implements RedisUtil{
|
public class TokenRedis implements RedisUtil {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
StringRedisTemplate stringRedisTemplate;
|
StringRedisTemplate stringRedisTemplate;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addRedis(String key, String value) {
|
public void addRedis(String key, String value) {
|
||||||
ValueOperations<String, String> valueOperations=stringRedisTemplate.opsForValue();
|
ValueOperations<String, String> valueOperations = stringRedisTemplate.opsForValue();
|
||||||
valueOperations.set(key,value,60, TimeUnit.MINUTES);
|
valueOperations.set(key, value, 60, TimeUnit.MINUTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -14,6 +14,7 @@ public class Email {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取
|
* 获取
|
||||||
|
*
|
||||||
* @return email
|
* @return email
|
||||||
*/
|
*/
|
||||||
public String getEmail() {
|
public String getEmail() {
|
||||||
|
@ -22,6 +23,7 @@ public class Email {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置
|
* 设置
|
||||||
|
*
|
||||||
* @param email
|
* @param email
|
||||||
*/
|
*/
|
||||||
public void setEmail(String email) {
|
public void setEmail(String email) {
|
||||||
|
@ -30,6 +32,7 @@ public class Email {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取
|
* 获取
|
||||||
|
*
|
||||||
* @return code
|
* @return code
|
||||||
*/
|
*/
|
||||||
public String getCode() {
|
public String getCode() {
|
||||||
|
@ -38,6 +41,7 @@ public class Email {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置
|
* 设置
|
||||||
|
*
|
||||||
* @param code
|
* @param code
|
||||||
*/
|
*/
|
||||||
public void setCode(String code) {
|
public void setCode(String code) {
|
||||||
|
|
|
@ -13,11 +13,14 @@ public class Result {
|
||||||
this.responseStr = responseStr;
|
this.responseStr = responseStr;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
public Result(int status){
|
|
||||||
this.status=status;
|
public Result(int status) {
|
||||||
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取
|
* 获取
|
||||||
|
*
|
||||||
* @return status
|
* @return status
|
||||||
*/
|
*/
|
||||||
public int getStatus() {
|
public int getStatus() {
|
||||||
|
@ -26,6 +29,7 @@ public class Result {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置
|
* 设置
|
||||||
|
*
|
||||||
* @param status
|
* @param status
|
||||||
*/
|
*/
|
||||||
public void setStatus(int status) {
|
public void setStatus(int status) {
|
||||||
|
@ -34,6 +38,7 @@ public class Result {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取
|
* 获取
|
||||||
|
*
|
||||||
* @return responseStr
|
* @return responseStr
|
||||||
*/
|
*/
|
||||||
public String getResponseStr() {
|
public String getResponseStr() {
|
||||||
|
@ -42,6 +47,7 @@ public class Result {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置
|
* 设置
|
||||||
|
*
|
||||||
* @param responseStr
|
* @param responseStr
|
||||||
*/
|
*/
|
||||||
public void setResponseStr(String responseStr) {
|
public void setResponseStr(String responseStr) {
|
||||||
|
@ -50,6 +56,7 @@ public class Result {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取
|
* 获取
|
||||||
|
*
|
||||||
* @return data
|
* @return data
|
||||||
*/
|
*/
|
||||||
public Object getData() {
|
public Object getData() {
|
||||||
|
@ -58,6 +65,7 @@ public class Result {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置
|
* 设置
|
||||||
|
*
|
||||||
* @param data
|
* @param data
|
||||||
*/
|
*/
|
||||||
public void setData(Object data) {
|
public void setData(Object data) {
|
||||||
|
|
|
@ -20,6 +20,7 @@ public class User {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取
|
* 获取
|
||||||
|
*
|
||||||
* @return username
|
* @return username
|
||||||
*/
|
*/
|
||||||
public String getUsername() {
|
public String getUsername() {
|
||||||
|
@ -28,6 +29,7 @@ public class User {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置
|
* 设置
|
||||||
|
*
|
||||||
* @param username
|
* @param username
|
||||||
*/
|
*/
|
||||||
public void setUsername(String username) {
|
public void setUsername(String username) {
|
||||||
|
@ -36,6 +38,7 @@ public class User {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取
|
* 获取
|
||||||
|
*
|
||||||
* @return password
|
* @return password
|
||||||
*/
|
*/
|
||||||
public String getPassword() {
|
public String getPassword() {
|
||||||
|
@ -44,6 +47,7 @@ public class User {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置
|
* 设置
|
||||||
|
*
|
||||||
* @param password
|
* @param password
|
||||||
*/
|
*/
|
||||||
public void setPassword(String password) {
|
public void setPassword(String password) {
|
||||||
|
@ -52,6 +56,7 @@ public class User {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取
|
* 获取
|
||||||
|
*
|
||||||
* @return account
|
* @return account
|
||||||
*/
|
*/
|
||||||
public String getAccount() {
|
public String getAccount() {
|
||||||
|
@ -60,6 +65,7 @@ public class User {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置
|
* 设置
|
||||||
|
*
|
||||||
* @param account
|
* @param account
|
||||||
*/
|
*/
|
||||||
public void setAccount(String account) {
|
public void setAccount(String account) {
|
||||||
|
@ -68,6 +74,7 @@ public class User {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取
|
* 获取
|
||||||
|
*
|
||||||
* @return email
|
* @return email
|
||||||
*/
|
*/
|
||||||
public String getEmail() {
|
public String getEmail() {
|
||||||
|
@ -76,6 +83,7 @@ public class User {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置
|
* 设置
|
||||||
|
*
|
||||||
* @param email
|
* @param email
|
||||||
*/
|
*/
|
||||||
public void setEmail(String email) {
|
public void setEmail(String email) {
|
||||||
|
|
|
@ -32,8 +32,7 @@ public class InterceptorConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
registry.addMapping("/**")
|
registry.addMapping("/**").allowCredentials(true)//允许携带cookie
|
||||||
.allowCredentials(true)//允许携带cookie
|
|
||||||
.allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH", "OPTIONS", "HEAD")//允许访问的方法
|
.allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH", "OPTIONS", "HEAD")//允许访问的方法
|
||||||
.allowedOriginPatterns("*")//允许的跨域访问地址
|
.allowedOriginPatterns("*")//允许的跨域访问地址
|
||||||
.maxAge(3600 * 24);//options缓存时间
|
.maxAge(3600 * 24);//options缓存时间
|
||||||
|
|
|
@ -9,6 +9,7 @@ import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
public class JWTUtil {
|
public class JWTUtil {
|
||||||
private static final String tokenPassword = "uziCjb";
|
private static final String tokenPassword = "uziCjb";
|
||||||
|
|
||||||
public static String sign(String username) {//用用户名作为被加密的对象
|
public static String sign(String username) {//用用户名作为被加密的对象
|
||||||
String token;
|
String token;
|
||||||
|
|
||||||
|
@ -18,13 +19,13 @@ public class JWTUtil {
|
||||||
.sign(Algorithm.HMAC256(tokenPassword));
|
.sign(Algorithm.HMAC256(tokenPassword));
|
||||||
return token;//返回加密后的token
|
return token;//返回加密后的token
|
||||||
}
|
}
|
||||||
public static String verify(String token){
|
|
||||||
JWTVerifier jwtVerifier=JWT.require(Algorithm.HMAC256(tokenPassword)).withIssuer("llh").build();//构建一个jwt解码器
|
public static String verify(String token) {
|
||||||
DecodedJWT jwtToken=jwtVerifier.verify(token);//解码
|
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(tokenPassword)).withIssuer("llh").build();//构建一个jwt解码器
|
||||||
if(token.isEmpty()){//若token为空则返回false拦截
|
DecodedJWT jwtToken = jwtVerifier.verify(token);//解码
|
||||||
|
if (token.isEmpty()) {//若token为空则返回false拦截
|
||||||
return null;
|
return null;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
System.out.println("认证通过:");
|
System.out.println("认证通过:");
|
||||||
System.out.println("issuer: " + jwtToken.getIssuer());
|
System.out.println("issuer: " + jwtToken.getIssuer());
|
||||||
System.out.println("username: " + jwtToken.getClaim("username").asString());
|
System.out.println("username: " + jwtToken.getClaim("username").asString());
|
||||||
|
|
|
@ -34,7 +34,7 @@ public class TokenInterceptor implements HandlerInterceptor {
|
||||||
if (token != null) {
|
if (token != null) {
|
||||||
String verifyToken = JWTUtil.verify(token);
|
String verifyToken = JWTUtil.verify(token);
|
||||||
|
|
||||||
if (redisUtil.getRedis(verifyToken)!=null) {
|
if (redisUtil.getRedis(verifyToken) != null) {
|
||||||
response.setStatus(200);//设置状态码为正常,即通过登录验证
|
response.setStatus(200);//设置状态码为正常,即通过登录验证
|
||||||
System.out.println("通过拦截器");
|
System.out.println("通过拦截器");
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -8,9 +8,10 @@ import javax.annotation.Resource;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class CodeCheck {
|
public class CodeCheck {
|
||||||
@Resource(name="codeRedis")
|
@Resource(name = "codeRedis")
|
||||||
RedisUtil codeRedis;
|
RedisUtil codeRedis;
|
||||||
public boolean CheckCode(String account,String code){
|
|
||||||
|
public boolean CheckCode(String account, String code) {
|
||||||
return code.equals(codeRedis.getRedis(account));
|
return code.equals(codeRedis.getRedis(account));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import org.springframework.stereotype.Service;
|
||||||
@Service
|
@Service
|
||||||
public class CodeCreate {
|
public class CodeCreate {
|
||||||
|
|
||||||
public String CreateCode(){
|
public String CreateCode() {
|
||||||
String[] letters = new String[]{
|
String[] letters = new String[]{
|
||||||
"0", "1", "2", "3", "4", "5", "6", "7",
|
"0", "1", "2", "3", "4", "5", "6", "7",
|
||||||
"8", "9"
|
"8", "9"
|
||||||
|
|
|
@ -27,12 +27,11 @@ public class LoginService {
|
||||||
|
|
||||||
|
|
||||||
if (user.getPassword().equals(requestUser.getPassword())) {
|
if (user.getPassword().equals(requestUser.getPassword())) {
|
||||||
String token= JWTUtil.sign(user.getAccount());
|
String token = JWTUtil.sign(user.getAccount());
|
||||||
redisUtil.addRedis(user.getAccount(),token);
|
redisUtil.addRedis(user.getAccount(), token);
|
||||||
return token;
|
return token;
|
||||||
} else return null;
|
} else return null;
|
||||||
}else
|
} else {
|
||||||
{
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ import java.util.Properties;
|
||||||
public class MailUtil {
|
public class MailUtil {
|
||||||
@Resource
|
@Resource
|
||||||
CodeCreate codeCreate;
|
CodeCreate codeCreate;
|
||||||
@Resource(name ="codeRedis")
|
@Resource(name = "codeRedis")
|
||||||
RedisUtil redisUtil;
|
RedisUtil redisUtil;
|
||||||
|
|
||||||
public void sendMail(String receive) {
|
public void sendMail(String receive) {
|
||||||
|
@ -44,7 +44,7 @@ public class MailUtil {
|
||||||
Message message = createSimpleMail(session, receive, code);
|
Message message = createSimpleMail(session, receive, code);
|
||||||
transport.sendMessage(message, message.getAllRecipients());
|
transport.sendMessage(message, message.getAllRecipients());
|
||||||
transport.close();
|
transport.close();
|
||||||
redisUtil.addRedis(receive,code);
|
redisUtil.addRedis(receive, code);
|
||||||
} catch (GeneralSecurityException | MessagingException e) {
|
} catch (GeneralSecurityException | MessagingException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
</delete>
|
</delete>
|
||||||
<update id="updateUser">
|
<update id="updateUser">
|
||||||
update user
|
update user
|
||||||
set password=#{password} and username = #{username} and email=#{email}
|
set password=#{password} and username = #{username} and email = #{email}
|
||||||
where account = #{account};
|
where account = #{account};
|
||||||
</update>
|
</update>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
Loading…
Reference in New Issue