faq点赞开发问题记录

本文围绕Spring Boot项目展开,涵盖数据库操作与项目部署问题。解决了插入查询数据库报错、TooManyResultsException等问题,介绍了MyBatis取值符号区别,还处理了Druid异常、MySQL中文乱码等。在项目部署方面,解决了打war包、多项目部署报错及上传war包问题,最后提及点赞传值实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

插入和查询数据库报错,不知是什么原因,语句问题?

@Insert("insert into like_log(ip,question,like,dislike) values (#{ip},#{question},#{like},#{dislike})")
    @Options(keyColumn = "id", keyProperty = "id",useGeneratedKeys = true)
    void insertLikeLog( LikeLog likeLog);

问题解决:
创建数据表时不能将MySQL的关键字作为字段名,这里我起了like的字段,正是MySQL关键字。将like改为like_count,果然还是不能偷懒。
5.7版本官方关键字列表

报错TooManyResultsException:

Exception in thread "main" org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 20

来看看mapper层:

@Select("select like_count,dislike_count from like_log where question= #{question} and ip= #{ip}")
    @Results({
            @Result(property = "like", column = "like_count"),
            @Result(property = "dislike", column = "dislike_count"),
    })
    LikeCollection searchLikeLog(@Param("ip") String ip, @Param("question") String question);

报错信息很明白,表示他找到了20个结果,但是你只用一个对象来接收,那这个对象该选谁呢,选择太多看来也不行。等等,这句话List跟map不是很同意,他们两可是花花世界的一匹狼。
解决方案:将接收对象定义为list类型如:List<LIkeCollection>,这里我只想拿到的是一个数据,而数据库里错误的有了两条记录,做数据测试时留下的删了即可。

MySQL报错解决–Parameter index out of range (1 > number of parameters, which is 0)

出现这种问题多半是SQL语句出了问题,一般控制台也会告诉你哪里出错了,但有时候你还是不知道错在哪里,错就错在你不了解基本的SQL语句。恩,说了等于没说。
比如我这里:

@Select("select like_count,dislike_count from like_log where question= ’#{question}‘ and ip= #{ip}")

这里我硬生生的在#{question}两边加了个引号’’,直接结果就是上述错误了。

mybatis中取值符号#,$的区别

  1. #The incoming data as a string, the incoming data to automatically add a double quotation marks. Such as: order by #{user_id}, if the incoming value is 111, then parsed into SQL values for the order by’111’, if its value is ID, then parsed into SQL order by ‘id’.
  2. $The incoming data directly display generation in sql. Such as: order by ${user_id}, if the incoming value is 111, then parsed into SQL when the value of order by 111, if its value is ID, then parsed into SQL order by ID.
  3. #Can significantly prevent SQL injection.
    4. U n a b l e t o p r e v e n t S q l i n j e c t i o n . 5. Unable to prevent Sql injection. 5. UnabletopreventSqlinjection.5.General way for incoming database objects, such as into the table name, column names
    6 in general can be used # don’t use$.
    Need to pay attention to using the order by dynamic parameters of MyBatis ranking, with $instead#

String replace
By default, the use of #{} format syntax will cause MyBatis to create pretreatment statement attributes and used it as the setting value (such as security?). It is safe to do this very quickly, also is the preferred approach, sometimes you just want to directly insert a does not change the string in the SQL statement. For example, like ORDER BY, you can use:
ORDER BY ${columnName}
This MyBatis does not modify or string literal.
Important: to accept from the user output and provides the string to the statement unchanged, it is unsafe to do so. This leads to potential SQL injection attacks, therefore you should not allow the user to enter these fields, or often to escape and check.
简单的说#可以防止sql注入的问题,而$不行,当然在用order排序和表名时必须要用dollar符。$传递的是数据库对象。

druid报异常 “sql injection violation, part alway true condition not allow”的解决方案

这是druid配置时设置了wall以防止sql注入,可以在配置文件里将其去掉

time-between-eviction-runs-millis: 60000
      # 配置连接在池中的最小生存时间
      min-evictable-idle-time-millis: 300000
      validation-query: select '1' from dual
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      # 打开PSCache,并且指定每个连接上PSCache的大小
      pool-prepared-statements: true
      max-open-prepared-statements: 20
      max-pool-prepared-statement-per-connection-size: 20
      # 配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙
      filters: stat
      #若去掉wall可以解决java.sql.SQLException: sql injection violation问题
      #part alway false condition not allow
      # Spring监控AOP切入点,如x.y.z.service.*,配置多个英文逗号分隔
      aop-patterns: com.springboot.servie.*

E45 readonly option is set (add ! to override)

编辑文件遇到权限问题,直接sudo就可以了

MySQL中文乱码问题

在my.cnf文件里添加:
my.cnf一般在/etc/mysql里,重启一下就ok。
参考链接

[mysqld]
character-set-server=utf8 
[client]
default-character-set=utf8 
[mysql]
default-character-set=utf8

MySQL数据库类型java类型对应表

数据库里定义的int类型,映射到Java里时需要用integer类型而不是int,如果使用int,数据库里的值为0时,拿到的值是null而不是0.
数据类型对应表

原因分析:Integer是包装类,便于类型转换,int是基本数据类型

项目部署

问题1:打war包

明明在springboot的application下运行的好好的,打包成war部署到tomcat上就是无法访问。
问题解决:
Web项目有三种运行方式:

  • jar包形式
  • 依赖于springboot自带的main函数
  • 依赖于外部服务器
    外部容器部署的话,就不能单单依赖于Application的main函数了,而是要以类似于web.xml文件配置的方式来启动Spring应用上下文,此时我们需要在启动类中继承SpringBootServletInitializer并实现configure方法:在application同级目录下创建一个ServletInitializer:是有两个启动类,一个是本来有的,这个是自定义的。
public class ServletInitializer extends SpringBootServletInitializer {
	@Override
	protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
		return application.sources(DemoApplication.class);
	}
}

完成启动类定义后,开始处理pom文件。
1.在pom里设置打包的格式,不标注的话默认是jar,这里要改为war。<packaging>war</packageing>
2.移除springboot-starter里的tomcat节点,因为项目即将要部署在服务器中的其他容器里,将有服务器里的tomcat提供服务。

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
         <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <scope>provided</scope>
        </dependency>

以上代码中,还可以看到添加了javax.servlet的相关依赖,其运行范围标注的是provided,这表名该依赖由运行环境提供,该依赖只生效于编译,测试期间,运行时不生效,更多关于scope的信息请参看我的另一篇文章:Maven之scope详解
为方便查看对照,我将整个pom文件贴在这里。
值得注意的是:此时打成的包的名称应该和application.properties的
server.context-path=/test保持一致。(目前faq是直接在前端写跳转的路径:/包名+跳转路径,添加了打包好的包名,contextpath的设置似乎并不成功)

test

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example.helloworld</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1</version>
    <packaging>war</packaging>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
            <version>2.0.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>faqtest</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

参考链接

问题2:Tomcat部署多个Spring boot+druid项目,启动报错。

先看看部署日志的错误提示:

Caused by: org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [com.alibaba.druid.filter.stat.StatFilter@5774d6    40] with key 'statFilter'; 
nested exception is javax.management.InstanceAlreadyExistsException: com.alibaba.druid.filter.stat:name=statFilter,type=    StatFilter

原因分析:同一个domain里MBean名字要求唯一,
解决方案:在配置文件里添加如下代码即可:

jmx:
    default-domain: my.company.domain
    #名字随意取

参考链接
更详细的分析

问题3:利用scp上传war包部署项目

在window上可以用winscp进行图形化管理远程服务器,实现文件交互,在使用scp时,直接上传到webapps目录下会出现边复制。tomcat边解压的情况,最后导致部署失败。所以最好先停掉tomcat服务,等上传完毕后再重新启动tomcat。
scp常用命令:
1.本地文件上传到远程服务器:scp /path/filename username@servername:/path
举个栗子:
scp /home/holytan/Desktop/work/source\ code/demo/target/faqtest.war root@192.168.212.112:/service/tomcat8.5/
2.复制文件到本地目录
例如:scp root@123.207.170.40:/root/test.txt /Users/mac/Desktop就是将服务器上的/root/test.txt下载到本地的/Users/mac/Desktop目录下。注意两个地址之间有空格!
更多参见

点赞传值实现

点赞,取消赞逻辑图

在这里插入图片描述

前端定义按钮动作

<div>

                <button class="btn btn-lg" onclick="like()" >
                    <i class="fas fa-thumbs-up"><p id="like" th:utext="${likecollection.like}"></p></i>
                </button>

                <button class="btn btn-lg" onclick="dislike()">
                    <i class="fas fa-thumbs-down"><p id="dislike" th:utext="${likecollection.dislike}"></p></i>
                </button>
            </div>

来看看p标签里的参数,id是为了跟下面的js配合,js会取到一个点赞后点赞总数的最新值,而th:utext取到的是未操作前的值,也就是用户刚进来时看到的初始值。下面来看看具体js做了什么。

<script th:inline="javascript">
        var ctx = [[@{/}]];
            function like() {
                var question = $( "p.h3" ).text();
                // var password = $("input[name='password']").val();
                // var rememberme = $("input[name='rememberme']").is(':checked');
                var like;
                $.ajax({
                    async:false,
                    type: "post",
                    url:  ctx+"like",
                    data: {"question": question},
                    dataType: "json",
                    success: function (r) {
                        like=r;
                        //alert(like);
                        if (r.code == 0) {
                            location.href = ctx + 'index';
                        } else {
                            // alert(r.msg);
                        }
                    }
                });
                document.getElementById("like").innerHTML=like;

            }
         </script>

为了使用变量,表达式,这里需要使用inline的模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值