搭建博客项目遇到的问题及解决办法

本文围绕Spring Boot开发展开,涵盖静态资源加载、注解使用、MyBatis映射、异常处理等内容。介绍了静态资源加载问题的解决办法,对比了MyBatis中resultMap和resultType的区别,阐述了多个注解的用法,还提及AOP日志处理、异常页面处理及项目部署等方面,并分享了部署时的问题及原因。

1.静态资源(图片)加载不出来

解决办法:在右边的maven中clean一下,再重启就ok了

2.@Repository的作用?

Spring的注解形式:@Repository、@Service、@Controller,它们分别对应存储层Bean,业务层Bean,和展示层Bean。

3.mybatis中resultMap和resultType的区别? 一定要区分开,不然会抛出异常

  • 基本映射 :(resultType)使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。(数据库,实体,查询字段,这些全部都得一一对应)
  • 高级映射 :(resultMap) 如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。(高级映射,字段名称可以不一致,通过映射来实现)

resultType和resultMap功能类似 ,都是返回对象信息 ,但是resultMap要更强大一些 ,可自定义。因为resultMap要配置一下,表和类的一一对应关系,所以说就算你的字段名和你的实体类的属性名不一样也没关系,都会给你映射出来,但是,resultType就比较鸡肋了,必须字段名一样,比如说 cId和c_id 这种的都不能映射 。

下面介绍几个常用的映射关系:

关联查询(一对一):resultMap对于一对一,在mapper.xml中采用association

关联查询(一对多):resultMap一对多,在mapper.xml中采用collection

4.mybatis bind 标签

<!--接口传入的值在pattern变量中,然后把传入的值拼接成"'%'+pattern+'%'"形式,放入Pattern参数中-->

5.自定义异常

为什么要自定义异常?

举个例子吧 假如说有个业务需求 返回1就应该报异常 但是JAVA 里面自带的不会有这种异常 ,这时候就需要自己定异常了!

6.@Param注解的用法

一.xml形式

实例一 @Param注解单一属性

dao层示例    (只有一个参数 貌似可以不用这样写)

Public User selectUser(@param(“userName”) String name, @param(“userpassword”) String password);

xml映射对应示例

<select id=" selectUser" resultMap="BaseResultMap">  
    select  *  from user_user_t 
        where user_name = #{userName,jdbcType=VARCHAR} and user_password=#{userPassword,jdbcType=VARCHAR}  
</select>

注意:采用#{}的方式把@Param注解括号内的参数进行引用(括号内参数对应的是形参如 userName对应的是name);

实例二 @Param注解JavaBean对象

dao层示例

public List<user> getUserInformation(@Param("user") User user);

xml映射对应示例

<select id="getUserInformation" parameterType="com.github.demo.vo.User" resultMap="userMapper">  
    select   
        <include refid="User_Base_Column_List"/>  
    from mo_user t where 1=1  
        <!-- 因为传进来的是对象所以这样写是取不到值得 -->  
        <if test="user.userName!=null and user.userName!=''"> and t.user_name = #{user.userName} </if>  
        <if test="user.userAge!=null and user.userAge!=''"> and t.user_age = #{user.userAge} </if>  
</select>  

二.注解形式

1,使用@Param注解

当以下面的方式进行写SQL语句时:

    @Select("select column from table where userid = #{userid} ")
    public int selectColumn(int userid);

当你使用了使用@Param注解来声明参数时,如果使用 #{} 或 ${} 的方式都可以。

    @Select("select column from table where userid = ${userid} ")
    public int selectColumn(@Param("userid") int userid);

当你不使用@Param注解来声明参数时,必须使用使用 #{}方式。如果使用 的方式,会报错。∗∗或者在mybatis中mapper文件中像这样写的方式,会报错。∗∗或者在mybatis中mapper文件中像这样写{_parameter},你只需要传入一条String类型的字符串。sql语句他就可以直接执行了,所以可以在动态配置的时候使用到该参数的含义:当只有一个参数,可以使用_parameter,它就代表了这个参数,如果使用@Param的话,会使用指定的参数值代替**

    @Select("select column from table where userid = ${userid} ")
    public int selectColumn(@Param("userid") int userid);

2,不使用@Param注解

不使用@Param注解时,参数只能有一个,并且是Javabean。在SQL语句里可以引用JavaBean的属性,而且只能引用JavaBean的属性。

    // 这里id是user的属性
    @Select("SELECT * from Table where id = ${id}")
    Enchashment selectUserById(User user);

7.@Valid注解的使用

在 Maven 配置中引入 @valid 的依赖:

如果你是 springboot 项目,那么可以不用引入了,已经引入了,他就存在于最核心的 web 开发包里面  注意版本是2.2.5的  如果是2.2.0的注解就不生效!!!

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.5.5.RELEASE</version>
</dependency>

用于验证注解是否符合要求,直接加在变量user之前,在变量中添加验证信息的要求,当不符合要求时就会在方法中返回message 的错误提示信息。

 

8.aop做日志处理

采用SpringBoot中的AOP进行日志处理,AOP可以以切面的形式拦截,将日志内容记录下来,这里记录以下日志信息:

  • 访问的URL
  • 访问者的IP
  • 访问时调用的方法
  • 访问时传递的参数
  • 访问时返回的内容

1.添加依赖

在pom.xml中添加AOP的依赖

<!--AOP-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

2.切面处理

在com.ggqq文件夹下面新建aspect包,创建LogAspect日志切面处理类,在这里对日志进行处理,代码如下:

package com.ggqq.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;


@Aspect
@Component
public class LogAspect {
    //获取日志信息
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    //定义切面,申明log()是一个切面
    @Pointcut("execution(* com.ggqq.controller.*.*(..))")
    public void log() {}

    //在切面之前执行
    @Before("log()")
    public void doBefore(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //获取URL、IP
        String url = request.getRequestURL().toString();
        String ip = request.getRemoteAddr();
        //获取请求方法
        String classMethod = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        //获取请求参数
        Object[] args = joinPoint.getArgs();
        RequestLog requestLog = new RequestLog(url, ip, classMethod, args);
        logger.info("Request : {}", requestLog);
    }

    //在切面之后执行
    @After("log()")
    public void doAfter() {
//        logger.info("--------doAfter--------");
    }

    //返回之后拦截
    @AfterReturning(returning = "result",pointcut = "log()")
    public void doAfterRuturn(Object result) {
        logger.info("Result : {}", result);
    }

//    封装请求参数
    private class RequestLog {
        private String url;
        private String ip;
        private String classMethod;
        private Object[] args;

        public RequestLog(String url, String ip, String classMethod, Object[] args) {
            this.url = url;
            this.ip = ip;
            this.classMethod = classMethod;
            this.args = args;
        }

        @Override
        public String toString() {
            return "{" +
                    "url='" + url + '\'' +
                    ", ip='" + ip + '\'' +
                    ", classMethod='" + classMethod + '\'' +
                    ", args=" + Arrays.toString(args) +
                    '}';
        }
    }
}

分析:

  • @Aspect注解:AOP切面作用
  • @Component注解:开启组件扫描,通过注解找到要扫描的对象
  • @Pointcut("execution(* com.star.controller..(..))"):定义切面,申明log()是一个切面,通过execution来表示需要拦截的类,这里表示拦截控制器下面的所有类所有方法
  • RequestLog:将请求的参数封装成一个内部类
  • 在访问页面(controller)之前,拦截请求的URL、IP、调用的方法、传递的参数、返回的内容,并记录到日志

运行项目,访问http://localhost:8080/,可以在控制台看到打印日志信息,记录了请求的URL、IP、调用的方法、传递的参数、返回的内容,并输入到了日志

 

 

9.异常处理

在页面访问的时候,会有一些比较常见的异常报错信息,比如路径无法访问404异常、服务器错误500异常以及自己定义的错误页面等等,SpringBoot框架提供了处理错误页面的方法,在这里,咱们对404、500、error异常页面进行处理。

1.定义错误页面

可以在前端页面templates目录下有error文件夹,SpringBoot可以通过文件夹的名称和错误文件命名的方式找到异常页面,所以文件名称只能固定,有以下异常页面:

  • 404.html
  • 500.html
  • error.html

可以通过控制器来测试一下,在com.ggqq文件夹下面新建controller包,创建IndexController控制器作为首页控制器,代码如下:

package com.ggqq.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;


@Controller
public class IndexController {
    //通过get方式请求路径
    @GetMapping("/")
    public String index(){
        return "index";
    }
}

404页面测试:可以在在浏览器输入:http://localhost:8080/ ,可以访问到博客的首页,可以通过改变路径,如加一个无效的后缀,访问后发现跳转到我自己写的404页面

500页面测试:可以在IndexController控制器中加一句错误代码,人为的让服务器出错,如加一句:int a = 9/0; (分母不能为零,这样服务器就会出错),然后访问:http://localhost:8080/, 发现跳转到了500页面,这就说明没有问题(记得把导致500的错误注释掉)

2.全局异常处理

对于404和500错误页面,SpringBoot可以根据页面的命名方式找到对应的文件,而自定义的错误就需要我们自己来拦截了,让代码出现问题的时候跳转到我们自己定义的错误页面,这里就需要自定义拦截器。

在com.ggqq文件夹下面新建hander包,创建ControllerExceptionHandler错误页面拦截器,通过定义这个类来拦截所有的异常,代码如下:

package com.ggqq.controller.hander;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;


@ControllerAdvice
public class ControllerExceptionHandler {

//    将异常记录到日志
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * @Description: 处理错误信息
     * @Auther: ONESTAR
     * @Date: 21:52 2020/5/20
     * @Param: request:访问的异常URL
     * @Param: e:异常参数
     * @Return: 返回错误信息页面
     */
    @ExceptionHandler(Exception.class)
    public ModelAndView exceptionHander(HttpServletRequest request, Exception e) throws Exception {

//        记录异常信息:请求的URL,异常信息
        logger.error("Requst URL : {},Exception : {}", request.getRequestURL(),e);

//        当标识了状态码的时候就不拦截
        if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) {
            throw e;
        }

//        将记录的异常信息返回到error页面
        ModelAndView mv = new ModelAndView();
        mv.addObject("url",request.getRequestURL());
        mv.addObject("exception", e);
        mv.setViewName("error/error");
        return mv;
    }
}

分析:

  • @ControllerAdvice表示拦截掉所有带有@Controller注解的控制器
  • @ExceptionHandler表明是异常处理方法
  • ModelAndView:返回一个页面信息
  • 通过拦截异常信息,在日志中记录,并返回给error页面
  • 标识了状态码的时候就不拦截,如资源找不到异常

3.资源找不到异常处理

对于资源找不到异常,一般也是要跳转到404页面的,这里就需要自定义一个异常类,专门用来应对资源找不到,在com.ggqq文件夹下面新建NotFoundException类。

package com.ggqq;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;


@ResponseStatus(HttpStatus.NOT_FOUND)
public class NotFoundException extends RuntimeException{
    public NotFoundException() {
    }

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

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

分析:

  • 继承RuntimeException,实现继承RuntimeException的构造函数
  • @ResponseStatus(HttpStatus.NOT_FOUND)注解表示资源找不到的状态码,标识了状态码的时候就不拦截

10.部署项目

部署:

 nohup java -jar myblog-0.0.1-SNAPSHOT.jar >temp.txt &

查看某个端口:

lsof -i:8081

启动

执行 cd 文件夹路径 命令进入jar包所在文件夹
后台运行jar包:

   nohup java -jar ***.jar &

nohub 表示后台不挂断运行
如需将日志输出到指定文件,在&前面加上>***.log ,如下:
(使用>为覆盖源文件,使用 >> 则为续写文件)

   nohup java -jar ***.jar >***.log &

关闭

方法一:
执行 ps -ef|grep java 命令查看当前正在运行的java进程,结果如下,第二列为进程PID

   root     20032     1  0 Jan01 ?        00:00:00 sudo nohup java -jar myblog.jar
   root     20033 20032  0 Jan01 ?        00:55:54 java -jar myblog.jar
   root     26038     1  0  2019 ?        00:00:00 sudo nohup java -jar IctExam.jar
   root     26039 26038  0  2019 ?        06:51:08 java -jar IctExam.jar
   root     28443  9171  0 21:47 pts/3    00:00:00 grep --color=auto java

方法二:
执行pidof java 或者 jps 查看现有jar包进程PID
执行 kill -9 PID 结束该PID对应的进程
 

11.部署项目时遇到了一个天坑!!!(浪费了3个小时)

springboot项目在本地可以运行,但是放到服务器上会报 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)问题

原因是

包名大写了!!! 。。。。。

 

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值