4)点击 Generate Project 生成下载项目
Project build error: Non-resolvable parent POM for com.example.hs:demo:0.0.1-SNAPSHOT: Failure to transfer org.springframework.boot:spring-boot-starter-parent:pom:
2.0.3.RELEASE from https://repo.maven.apache.org/maven2 was cached in the local repository, resolution will not be reattempted until the update interval of central has
elapsed or updates are forced. Original error: Could not transfer artifact org.springframework.boot:spring-boot-starter-parent:pom:2.0.3.RELEASE from/to central (https://
repo.maven.apache.org/maven2): Received fatal alert: protocol_version and 'parent.relativePath' points at no local POM
解决方案:打开终端,进入出错项目的根目录,然后使用 maven bin 目录下的 mvn 编译一下,完成之后右键项目 Maven——Update Project 即可。
F:\javaProjectNew\demo>mvn compile
3、在springboot中配置除了支持application.properties,还支持application.yml的配置方式。
4、异常处理类方式(以权限为例)--springMVC
1)权限错误时抛出此异常
package com.ex.exception;
public class AuthException extends RuntimeException {
private static final long serialVersionUID = 1L;
public AuthException(final String msg) {
super(msg);
}
public AuthException(final String msg, final Throwable exception) {
super(msg, exception);
}
}
2)全局异常处理
package com.ex.util;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import com.ex.exception.AuthException;
@ControllerAdvice(annotations = { RestController.class })
public class ExceptionUtil implements ExceptionMapper {
private final static Logger LOGGER = LoggerFactory.getLogger(ExceptionUtil.class);
@Override
public Response toResponse(final Throwable exception) {
LOGGER.error("exception:[{}]", exception);
return Response.status(Status.BAD_REQUEST).entity(ResponseUtil.errorRes(exception.getMessage()))
.type(MediaType.APPLICATION_JSON).build();
}
@ExceptionHandler
@ResponseStatus(value = HttpStatus.OK)
public @ResponseBody ResponseUtil exception(final HttpServletRequest request, final Exception exception) {
final ResponseUtil resp = new ResponseUtil(false);
final String url = request.getRequestURL().toString();
LOGGER.error("the request is:[{}] and the exception is:[{}]", url, exception);
if (exception instanceof AuthException) {
resp.setErrorMsg("no permission");
}
resp.setErrorMsg(exception.getLocalizedMessage());
return resp;
}
}
其中核心内容如下:
@ControllerAdvice(annotations = { RestController.class })
3)自定义注解~~(PointCut连接点注解类)
package com.ex.anno;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)//定义注解在JVM运行时保留,在运行是通过反射机制获取
@Target(ElementType.METHOD)//定义注解的作用目标**作用范围字段、枚举的常量/方法
@Documented//说明该注解将被包含在javadoc中
public @interface Authorize {
public String value() default "";
}
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。
自定义注解的作用:在反射中获取注解,以取得注解修饰的类、方法或属性的相关解释。
4)AOP切面
@Aspect//定义切面
@Component
public class AuthAspect {
@Autowired
private transient AuthBO authBO;
//环绕通知:定义@Around增强,pointcut连接点使用@annotation(xxx)定义,其中xxx对应该方法中final Authorize authorize参数authorize
@Around(value = "@annotation(authorize)")
public Object doAuthorize(final ProceedingJoinPoint joinPoint, final Authorize authorize) throws Throwable {
final String value = authorize.value();
if (value != null && !"".equals(value)) {
// 调用方法名
final String methodName = value.substring(0, value.indexOf('('));
// 资源编号
final String code = value.substring(value.indexOf('\'') + 1, value.lastIndexOf('\'')).replaceAll("\'", "").replaceAll("\\s*", "");
final Boolean flag = new ReflectTask(authBO, methodName, new Class[] { String.class }, new Object[] { code }).call();
if (!flag) {
throw new AuthException("权限错误!");
}
}
return joinPoint.proceed();//调用目标方法
}
}
在上面定义@Around增强时,通过@annotation() 方式指定了pointcut,其中方法参数为连接点注解类Authorize;
package com.ex.service;
import org.springframework.stereotype.Component;
import com.ex.anno.Authorize;
@Component
public class LoginService {
@Authorize(value="admin")//表示需要对该方法进行@Around增强处理
public String getSomething(){
return "HelloWord";
}
}
5、登录日志简单示例
1)自定义LoginLog注解类
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
@Inherited
public @interface LoginLog {
}
2)日志切点类
@Aspect
@Component
@ConditionalOnProperty(name = "exsystem.isLog", havingValue = "true")
public class LogAspect {
@Autowired
private transient LogsBO logsBO;
private final static Logger LOGGER = LoggerFactory.getLogger(LogAspect.class);
@Around(value = "within(cn.ex..*) && @annotation(loginLog)")
public Object doLoginLog(final ProceedingJoinPoint joinPoint, final LoginLog loginLog) throws Throwable {
// 调用参数
final Object[] args = joinPoint.getArgs();
final Object obj = joinPoint.proceed(args);
try {
logsBO.writeLoginLog(obj, args);
} catch (Exception e) {
LOGGER.error("创建登录日志异常,异常信息:{}", e.getMessage());
}
return obj;
}
}
其中SpringBoot通过@ConditionalOnProperty来控制Configuration是否生效,其中name用来从application.yml中读取某个属性值,如果该值为空,则返回false;如果值不为空,则将该值与havingValue指定的值进行比较;
另外通过环绕通知@Around对cn.ex..*包下类以及所有加了LoginLog注解的方法体进行切入拦截,如上代码会进入doLoginLog里进行logsBO.writeLoginLog(obj, args);将登录日志入数据库处理。
3)切入点
@RestController
@RequestMapping("/login")
public class LoginServerResource {
/**
* 登录操作
*
* @param loginName 用户名
* @param password 密码
* @param checkCode 验证码
* @return
*/
@LoginLog
@RequestMapping(value = "/login", method = { RequestMethod.POST }, consumes = { MediaType.APPLICATION_FORM_URLENCODED_VALUE })
public ModelAndView login(final @ModelAttribute(value = "loginName") String loginName,
final @ModelAttribute(value = "password") String password,
final @ModelAttribute(value = "checkCode") String checkCode,
final @ModelAttribute(value = "phoneCode") String phoneCode) {
return null;
}
}
通过@LoginLog自定义注解切入。
...