Spring Boot project 第四篇-实训项目day3

1.搭建环境:JDK1.8+IDEA2017+MySQL8.0

2.功能要求:

登录功能:

1. 用户名为6-20位字符串,支持字母、数字;

2. 密码为8-20位字符串,支持字母、数字、特殊字符;

3. 登录失败有原因提示;

4. 5分钟内5次登录失败冻结账号10分钟;

注册功能:

1. 注册信息包括用户名、密码、手机号、出生年月、性别;

2. 用户名、手机号不可重复;

3. 用户名为6-20位字符串,支持字母、数字;

4. 密码为8-20位字符串,支持字母、数字、特殊字符;

5. 验证手机号格式;

6. 注册失败有原因提示;

3.登录实现

3.1编写UserService类

package com.example.shop.service;

import com.example.shop.model.User;

public interface UserService {

    Integer checkLoginLog(User user);

    User login(User user, String ip);

    Integer reg(User user);
}

3.2编写实现类

package com.example.shop.service.impl;

import com.example.shop.dao.LoginLogDAO;
import com.example.shop.dao.LoginLogSpecDAO;
import com.example.shop.dao.UserDAO;
import com.example.shop.model.LoginLog;
import com.example.shop.model.LoginLogExample;
import com.example.shop.model.User;
import com.example.shop.model.UserExample;
import com.example.shop.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

import java.util.Date;
import java.util.List;


@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDAO userDAO;

   /* @Autowired
    private LoginLogDAO loginLogDAO;

    @Autowired
    private LoginLogSpecDAO loginLogSpecDAO;*/

    /**
     * 检查登录失败次数
     */
 /*   @Override
    public Integer checkLoginLog(User user){
        //判断该账号是否可以登录
        LoginLog loginLog = new LoginLog();
        loginLog.setUsername(user.getUsername());
        return loginLogSpecDAO.countByUsername(loginLog);
    }*/


    /**
     * 登录验证用户名和密码
     * @param user
     * @return
     */
    @Override
    public User login(User user, String ip) {
        //判断用户名密码是否存在
        UserExample userExample = new UserExample();
        userExample.createCriteria().andUsernameEqualTo(user.getUsername()).andPasswordEqualTo(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
        List<User> users = userDAO.selectByExample(userExample);

      /*  //增加登录日志
        int flag = !CollectionUtils.isEmpty(users) ? 1 : 0;
        LoginLog loginLog = new LoginLog();
        loginLog.setUsername(user.getUsername());
        loginLog.setIp(ip);
        loginLog.setLoginTime(new Date());
        loginLog.setLoginSuccess(flag);
        loginLogDAO.insertSelective(loginLog);*/

        return !CollectionUtils.isEmpty(users) ? users.get(0) : null;
    }

    /**
     * 新用户注册
     * @param user
     * @return
     */
    @Override
    public Integer reg(User user){
        //判断手机号和用户名是否重复
        UserExample ue = new UserExample();
        ue.createCriteria().andUsernameEqualTo(user.getUsername());
        ue.or().andPhoneEqualTo(user.getPhone());
        List<User> users = userDAO.selectByExample(ue);
        if(!CollectionUtils.isEmpty(users)){
            return -1;
        }

        //密码加密,增加创建时间,注册用户信息
        user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
        user.setCreatedTime(new Date());
        int rs = userDAO.insertSelective(user);

        //如果添加成功,获取刚插入的id
        if(rs > 0){
            return user.getId();
        }
        return rs;
    }
}

3.3校验功能有两种方式:第一种使用正则表达式

package com.example.shop_test.controller;


import com.example.shop_test.common.util.JwtUtils;
import com.example.shop_test.common.util.ResultModel;
import com.example.shop_test.model.User;
import com.example.shop_test.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    UserService userService;

    /**
     * 用户登录
     * @param user
     * @return
     */
    @PostMapping("/login")
    @ResponseBody
    public ResultModel login(@RequestBody User user){
        //验证参数,也可以使用validated
        if(null == user.getUsername()){
            return ResultModel.error("请输入用户名");
        }
        String userExp = "^[A-Za-z0-9]{6,20}$";
        if(!user.getUsername().matches(userExp)) {
            return ResultModel.error("用户名为6-20位字母、数字");
        }
        if(null == user.getPassword()){
            return ResultModel.error("请输入密码");
        }
        String pwdExp = "^[A-Za-z0-9_!@#$%&*]{8,20}$";
        if(!user.getPassword().matches(pwdExp)) {
            return ResultModel.error("密码为8-20位字母、数字、特殊字符");
        }

        //调用登录方法
        User rs = userService.login(user);
        if(null == rs){
            return ResultModel.error("用户名密码错误");
        }

        //jwt 封装token返回给前端 后续接口用token验证身份
        String token = JwtUtils.createToken(rs.getId(), rs.getUsername());
        Map resultMap = new HashMap();
        resultMap.put("id", rs.getId());
        resultMap.put("token", token);
        return ResultModel.success(resultMap);

    }

    /**
     * 用户注册
     * @param user
     * @return
     */
    @PostMapping("reg")
    @ResponseBody
    public ResultModel reg(@RequestBody User user){

        Integer rs = userService.reg(user);

        if(0 == rs){
            return ResultModel.error("注册失败");
        }

        //jwt 封装token返回给前端 后续接口用token验证身份
        String token = JwtUtils.createToken(rs, user.getUsername());
        Map resultMap = new HashMap();
        resultMap.put("id", rs);
        resultMap.put("token", token);
        return ResultModel.success(resultMap);
    }
}

第二种使用注解@Validated:

步骤如下:

(1)先创建两个接口Reg和Login

package com.example.shop.common.validation.user;

/**
 * 注册校验
 */
public interface Login {
}
package com.example.shop.common.validation.user;

/**
 * 注册校验
 */
public interface Reg {
}

(2)使用这两个接口绑定@Validated注解上(@Validated(Reg.class)

(3)在model模型中绑定属性值

package com.example.shop.model;

import com.example.shop.common.validation.user.Login;
import com.example.shop.common.validation.user.Reg;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import java.util.Date;

public class User {
    private Integer id;

    @NotBlank(message = "用户名不能为空",groups = {Reg.class, Login.class})
    @Pattern(regexp = "^[A-Za-z0-9]{6,20}$", message = "用户名格式错误", groups = {Reg.class, Login.class})
    private String username;

    @NotBlank(message = "密码不能为空",groups = {Reg.class, Login.class})
    @Pattern(regexp = "^[A-Za-z0-9_!@#$%&*]{8,20}$", message = "密码格式错误", groups = {Reg.class, Login.class})
    private String password;

    private String nickname;

    private Date birthday;

    private Integer sex;
    
    private String phone;

    private String idcardNum;

    private Integer status;

    private Date createdTime;

    private Date modifiedTime;

    private Integer isDelete;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public Integer getSex() {
        return sex;
    }

    public void setSex(Integer sex) {
        this.sex = sex;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public String getIdcardNum() {
        return idcardNum;
    }

    public void setIdcardNum(String idcardNum) {
        this.idcardNum = idcardNum;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public Date getCreatedTime() {
        return createdTime;
    }

    public void setCreatedTime(Date createdTime) {
        this.createdTime = createdTime;
    }

    public Date getModifiedTime() {
        return modifiedTime;
    }

    public void setModifiedTime(Date modifiedTime) {
        this.modifiedTime = modifiedTime;
    }

    public Integer getIsDelete() {
        return isDelete;
    }

    public void setIsDelete(Integer isDelete) {
        this.isDelete = isDelete;
    }
}

(4)导入ValidationExceptionHandler类(监听格式是否出错)

package com.example.shop.config;


import com.example.shop.common.util.ResultModel;
import com.example.shop.exception.LoginException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * validation
 */
@Slf4j
@RestControllerAdvice(basePackages = {"com.example"})
public class ValidationExceptionHandler {
    public ValidationExceptionHandler() {
    }

    @ExceptionHandler({MethodArgumentNotValidException.class})
    public ResultModel<?> validationErrorHandler(MethodArgumentNotValidException e) {
        List<String> errorInfo = e
                .getBindingResult()
                .getAllErrors()
                .stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .collect(Collectors.toList());
        log.error(errorInfo.toString());
        return new ResultModel(401, errorInfo.toString());
    }

    @ExceptionHandler({ConstraintViolationException.class})
    public ResultModel validationParamErrorHandler(ConstraintViolationException e) {
        List<String> errorInfo = e
                .getConstraintViolations()
                .stream()
                .map(ConstraintViolation::getMessage)
                .collect(Collectors.toList());
        log.error(errorInfo.toString());
        return new ResultModel(402, errorInfo.toString());
    }

}

3.4编写controller类

package com.example.shop.controller;

import com.example.shop.common.util.IpUtils;
import com.example.shop.common.util.JwtUtils;
import com.example.shop.common.validation.user.Login;
import com.example.shop.common.validation.user.Reg;
import com.example.shop.model.User;
import com.example.shop.service.UserService;
import com.example.shop.common.util.ResultModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    UserService userService;

    /**
     * 用户登录
     * @param user
     * @return
     */
    @PostMapping("/login")
    @ResponseBody
    public ResultModel login(@Validated(Login.class) @RequestBody User user, HttpServletRequest request){
      /*  //验证是否可以登录
        Integer count = userService.checkLoginLog(user);
        if(count > 4){
            return ResultModel.error("用户禁止登录");
        }*/

        //调用登录方法
        String ip = IpUtils.getIpAddr(request);
        User rs = userService.login(user, ip);
        if(null == rs){
            return ResultModel.error("用户名密码错误");
        }

        //jwt 封装token返回给前端 后续接口用token验证身份
        String token = JwtUtils.createToken(rs.getId(), rs.getUsername());
        Map resultMap = new HashMap();
        resultMap.put("id", rs.getId());
        resultMap.put("token", token);
        return ResultModel.success(resultMap);

    }

    /**
     * 用户注册
     * @param user
     * @return
     */
    @PostMapping("reg")
    @ResponseBody
    public ResultModel reg(@Validated(Reg.class) @RequestBody User user){

        Integer rs = userService.reg(user);

        if(0 == rs){
            return ResultModel.error("注册失败");
        }else if(-1 == rs){
            return ResultModel.error("用户名或手机已存在");
        }

        //jwt 封装token返回给前端 后续接口用token验证身份
        String token = JwtUtils.createToken(rs, user.getUsername());
        Map resultMap = new HashMap();
        resultMap.put("id", rs);
        resultMap.put("token", token);
        return ResultModel.success(resultMap);
    }
}

3.5拦截器的实现

(1)编写拦截器LoginInterceptor

package com.example.shop.common.interceptor;

import com.example.shop.common.util.JwtUtils;
import com.example.shop.exception.LoginException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Slf4j
@Configuration
public class LoginInterceptor implements HandlerInterceptor {

    /**
     * 验证登录状态
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = request.getHeader("token");
        if (StringUtils.isBlank(token)) {
            log.error("token为空或token已过期");
            throw new LoginException(400,"token为空或token已过期");
        }
        if (!JwtUtils.verify(token)) {
            log.error("token不正确");
            throw new LoginException(400, "token不正确");
        }
        String id = JwtUtils.getClaimByName(token, "id");
        String username = JwtUtils.getClaimByName(token, "username");
        request.getSession().setAttribute("id", id);
        request.getSession().setAttribute("username", username);
        return true;
    }
}

(2)定义自己的配置类 MyMvcConfig,加入拦截器

package com.example.shop.config;

import com.example.shop.common.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * 列举不需要验证登录状态的接口
 */
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**")
                .excludePathPatterns("/user/login")
                .excludePathPatterns("/user/reg");
    }
}

(3)定义一个异常类LoginException

package com.example.shop.exception;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginException extends RuntimeException{
    private int code;
    private String message;

    public LoginException(String message) {
        super(message);
    }

    public LoginException(String message, Throwable cause) {
        super(message, cause);
    }
}

3.6冻结登录实现

(1)自定义一个DAO类,LoginLogSpecDAO

package com.example.shop.dao;

import com.example.shop.model.LoginLog;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface LoginLogSpecDAO {
    int countByUsername(LoginLog loginLog);

}

(2)model类LoginLog自动生成Mybatis

package com.example.shop.model;

import java.util.Date;

public class LoginLog {
    private Integer id;

    private String username;

    private String ip;

    private Integer loginSuccess;

    private Date loginTime;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public Integer getLoginSuccess() {
        return loginSuccess;
    }

    public void setLoginSuccess(Integer loginSuccess) {
        this.loginSuccess = loginSuccess;
    }

    public Date getLoginTime() {
        return loginTime;
    }

    public void setLoginTime(Date loginTime) {
        this.loginTime = loginTime;
    }
}
<table tableName="login_log" domainObjectName="LoginLog" mapperName="LoginLogDAO" catalog="shop">
            <property name="ignoreQualifiersAtRuntime" value="true"/>
            <generatedKey column="id" sqlStatement="MySql" identity="true"/>
        </table>

(3)编写LoginLogSpecDAO.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.shop.dao.LoginLogSpecDAO">
    <!-- 根据用户id查询角色名称 -->
    <select id="countByUsername" parameterType="com.example.shop.model.LoginLog" resultType="java.lang.Integer">
        select count(id)
        from login_log
        where username = #{username}
        and login_time > DATE_SUB(NOW(),INTERVAL 5 MINUTE)
        and login_success = 0
    </select>

</mapper>

(4)重写实现类

package com.example.shop.service.impl;

import com.example.shop.dao.LoginLogDAO;
import com.example.shop.dao.LoginLogSpecDAO;
import com.example.shop.dao.UserDAO;
import com.example.shop.model.LoginLog;
import com.example.shop.model.LoginLogExample;
import com.example.shop.model.User;
import com.example.shop.model.UserExample;
import com.example.shop.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

import java.util.Date;
import java.util.List;


@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDAO userDAO;

    @Autowired
    private LoginLogDAO loginLogDAO;

    @Autowired
    private LoginLogSpecDAO loginLogSpecDAO;

    /**
     * 检查登录失败次数
     */
    @Override
    public Integer checkLoginLog(User user){
        //判断该账号是否可以登录
        LoginLog loginLog = new LoginLog();
        loginLog.setUsername(user.getUsername());
        return loginLogSpecDAO.countByUsername(loginLog);
    }


    /**
     * 登录验证用户名和密码
     * @param user
     * @return
     */
    @Override
    public User login(User user, String ip) {
        //判断用户名密码是否存在
        UserExample userExample = new UserExample();
        userExample.createCriteria().andUsernameEqualTo(user.getUsername()).andPasswordEqualTo(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
        List<User> users = userDAO.selectByExample(userExample);

        //增加登录日志
        int flag = !CollectionUtils.isEmpty(users) ? 1 : 0;
        LoginLog loginLog = new LoginLog();
        loginLog.setUsername(user.getUsername());
        loginLog.setIp(ip);
        loginLog.setLoginTime(new Date());
        loginLog.setLoginSuccess(flag);
        loginLogDAO.insertSelective(loginLog);

        return !CollectionUtils.isEmpty(users) ? users.get(0) : null;
    }

    /**
     * 新用户注册
     * @param user
     * @return
     */
    @Override
    public Integer reg(User user){
        //判断手机号和用户名是否重复
        UserExample ue = new UserExample();
        ue.createCriteria().andUsernameEqualTo(user.getUsername());
        ue.or().andPhoneEqualTo(user.getPhone());
        List<User> users = userDAO.selectByExample(ue);
        if(!CollectionUtils.isEmpty(users)){
            return -1;
        }

        //密码加密,增加创建时间,注册用户信息
        user.setPassword(DigestUtils.md5DigestAsHex(user.getPassword().getBytes()));
        user.setCreatedTime(new Date());
        int rs = userDAO.insertSelective(user);

        //如果添加成功,获取刚插入的id
        if(rs > 0){
            return user.getId();
        }
        return rs;
    }
}

3.7postman测试

3.8工具类

IpUtils

package com.example.shop.common.util;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;

public class IpUtils {
    public static String getIpAddr(HttpServletRequest request) {
        String ipAddress = null;
        try {
            ipAddress = request.getHeader("x-forwarded-for");
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
                ipAddress = request.getRemoteAddr();
                if (ipAddress.equals("127.0.0.1")) {
                    // 根据网卡取本机配置的IP
                    InetAddress inet = null;
                    try {
                        inet = InetAddress.getLocalHost();
                    } catch (UnknownHostException e) {
                        e.printStackTrace();
                    }
                    ipAddress = inet.getHostAddress();
                }
            }
            // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
            if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()
                // = 15
                if (ipAddress.indexOf(",") > 0) {
                    ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
                }
            }
        } catch (Exception e) {
            ipAddress="";
        }
        // ipAddress = this.getRequest().getRemoteAddr();

        return ipAddress;
    }
}

JwtUtils  

package com.example.shop.common.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;

/**
 * @author dhl
 * @datetime 2021/8/17  13:47
 */
public class JwtUtils {
    /**
     * 超时时间
     */
    private static final long TIME_OUT_MS = 1000 * 60 * 60 * 24;
    /**
     * 加密方式
     */
    private static final String ENCRYPT ="wqw123";
    /**
     * 算法
     */
    private static final Algorithm ALGORITHM = Algorithm.HMAC256(ENCRYPT);

    /**
     * 生成签名,30min后过期
     * @param id
     * @return
     */
    public static String createToken(Integer id, String username){
        Date date = new Date(System.currentTimeMillis() + TIME_OUT_MS);
        return JWT.create()
                // 设置荷载 payload
                .withClaim("id", id)
                .withClaim("username", username)
                // 设置过期时间
                .withExpiresAt(date)
                .sign(ALGORITHM);
    }

    /**
     * 验证token是否正确
     * @param token
     * @return
     */
    public static boolean verify(String token) {
        try {
            JWTVerifier verifier = JWT.require(ALGORITHM).build();
            verifier.verify(token);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 获取token中的信息
     * @param token
     * @param name
     * @return
     */
    public static String getClaimByName(String token, String name) {
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getClaim(name).asString();
    }
}

ResultModel 

package com.example.shop.common.util;

import lombok.Data;

@Data
public class ResultModel<T> {
    private int code;
    private String message="";
    private T content;
    public ResultModel(){
    }
    public ResultModel(int code,String message){
        this.code = code;
        this.message = message;
    }
    public ResultModel(int code,String message,T content){
        this.code = code;
        this.message = message;
        this.content = content;
    }
    public static <T> ResultModel<T> success(String message,T content){
        return new ResultModel<T>(0,message,content);
    }
    public static <T> ResultModel<T> success(T content){
        return new ResultModel<T>(0,"success",content);
    }
    public static <T> ResultModel<T> error(int code,String message){
        return new ResultModel<T>(code,message);
    }
    public static <T> ResultModel<T> error(String message){
        return new ResultModel<T>(-1,message);
    }
    public static <T> ResultModel<T> error(){
        return new ResultModel<T>(-1,"error");
    }
}

 

### Ideal Practices for a Spring Boot Project An ideal Spring Boot project adheres closely to established conventions and best practices within the software development community. For instance, when handling exceptions in such projects, one should aim at catching specific exceptions rather than just using `Exception`, which is the base class of all exceptions[^1]. However, there are scenarios where it might be necessary to catch all types of exceptions; this can be achieved by specifying `Exception` as the parameter type in the catch clause. In terms of technology stack familiarity, having knowledge in Java would significantly benefit developers working on Spring Boot applications since both technologies share common ground and principles[^2]. For structuring an optimal Spring Boot application: - **Project Structure**: Organize packages logically based on functionality (e.g., controllers, services, repositories). This approach enhances readability and maintainability. - **Configuration Management**: Utilize externalized configuration files like `.properties` or `.yml`. These configurations allow easy adjustments without altering source code directly. - **Dependency Injection & Inversion of Control**: Leverage these design patterns through annotations provided by Spring Framework (`@Autowired`, `@Component`, etc.) to manage dependencies effectively between components. - **Security Measures**: Implement security measures from day one utilizing libraries compatible with Spring Security framework ensuring data integrity and user authentication/authorization mechanisms. - **Testing Strategy**: Develop comprehensive unit tests alongside integration testing strategies employing tools like JUnit along with mocking frameworks such as Mockito. ```java // Example demonstrating dependency injection via constructor @Service public class UserService { private final UserRepository userRepository; public UserService(UserRepository userRepository) { this.userRepository = userRepository; } // Service methods... } ``` Regarding query optimization techniques mentioned previously about matching fields during searches, while not directly related to building Spring Boot apps, similar concepts apply when designing efficient database interactions within your service layer[^3].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Amo@骄纵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值