ThinkPHP 6.0文档

Composer安装

composer create-project topthink/think tp
# tp是应用根目录名称,可以修改

访问

  1. localhost/tp/public/ 首页
  2. 首页/index.php/index controller下的Index类
  3. 首页/index.php/index/?s=hello/value 调用controller下Index类的hello方法,并传入参数value(URL兼容模式)
  4. 首页/index.php/hello_world 调用controller下HelloWorld类
  5. 首页/index.php/group.blog 调用controller/group下的Blog类

输出数组

$data = array('a' => 1, 'b' => 2, 'c' => 3);
return json($data);

开启调试

在应用根目录下新建.env文件

APP_DEBUG = true

[APP]
DEFAULT_TIMEZONE = Asia/Shanghai

[DATABASE]
TYPE = mysql
HOSTNAME = 127.0.0.1
DATABASE = test
USERNAME = username
PASSWORD = password
HOSTPORT = 3306
CHARSET = utf8
DEBUG = true

[LANG]
default_lang = zh-cn

数据库

$user = Db::connect('mysql')->table('tp_user')->select();
// 确定数据库和数据表
return json($user);

// 或者有Model User
$user = User::select();

Model

<?php
namespace app\model;

use think\Model;

class User extends Model
{
protected $connection = 'databaseName';
}

查询

Db::getLastSql();可以看上一条sql语句

一条数据

Db::table('tableName')->where('fieldName', fieldValue)->find(); // 查询不到返回null
// findFail在查询不到时抛出异常;findEmpty在查询不到时返回空数组

整个表(数据集)

Db::table('tableName')->select();
Db::name('tableNameWithoutPrefix')->select();

某条记录的字段值

Db::name('tableName')->where('id', $id)->value('field');

一列(键值对)

Db::name('name')->column('fieldAsValue', 'fieldAsKey');

插入

一条数据

// strict 表示强行插入
Db::name('user')->strict(false)->insert($data);
// 有相同主键则替换
Db::name('user')->replace()->insert($data);
// 根据主键自动判断
Db::name('user')->save($data);

多条数据

Db::name('user')->insertAll($data);

修改

Db::name('user')->where('id', 232)
->update([
// 下面是SQL表达式
'email' => Db::raw('UPPER(email)'),
'price' => Db::raw('price + 1'),
'status'=> Db::raw('status - 2')
]);

删除

// 根据主键删除多条数据
Db::name('user')->delete([48,49,50]);
// 匹配删除
Db::name('user')->where('id', 47)->delete();
// 全部删除
Db::name('user')->delete(true);

模板

composer require topthink/think-view

1.0 Bar 柱状图

from pyecharts.charts import Bar

bar = Bar()
bar.add_xaxis(["衬衣", "羊毛衫", "西装", "裤子", "鞋子", "袜子"])
bar.add_yaxis("商家", [5, 20, 40, 10, 70, 90])
# 相当于
bar = (
Bar()
.add_xaxis(["衬衣", "羊毛衫", "西装", "裤子", "鞋子", "袜子"])
.add_yaxis("商家", [5, 20, 40, 10, 70, 90])
.add_yaxis("商家B", [15, 6, 45, 20, 35, 66]) # 支持两个柱子同时生成
.set_global_opts(title_opts=opts.TitleOpts(title="主标题", subtitle="副标题")) # 生成标题
)


bar.render("bar.html") # 渲染为 bar.html,默认是 render.html
  • 效果
阅读全文 »

Mysql体系结构

DB与Instance

DB:数据库可以是ibd文件、放在内存的文件,是物理操作系统文件或其他形式文件类型的集合。
Instance:Mysql数据库由后台线程及一个共享内存区组成。

数据库实例才是真正操作数据库文件的。在集群情况下,可能存在一个DB被多个Instance使用的情况。

Mysql被设计为单进程多线程,在OS上的表现是一个进程。

插件式表存储引擎

存储引擎基于表,而不是DB。

存储引擎对开发人员透明。

索引原理

MySQL使用的是B+树作为索引的数据结构

B树是一个分支内按顺序存放多个节点数据的数据结构;而B+树在此基础上,在分支内只存储索引,只在叶子节点存储数据(这样每一层可以存储更多索引,减少层数),并且在叶节点之间用指针互相连接,提高访问效率。

阅读全文 »

一号标题

Title 2

三号标题

Title 4

五号标题
Title 6

标题 Title 标题
左对齐 Justify Align 右对齐
  • 无序列表
    • Unordered List
  1. 有序列表
    2. Ordered List
  • [x] 待办事项
  • [] TO-DO List

Delete Line
Blod
Italic
Code
E=MC2E = MC^2
Link

[1]Hello, World![2]

public static void main(String[] args) {
System.out.println("Hello World!");
}
--- auto_detect: ture
+++ auto_detect: false

No Silver Bullet

By Brooks

[!NOTE]
Note that it is a note.

[!WARNING]
WARNING!

[!DANGER]
Notice the DANGER!

[!SUCCESS]
Now it is SUCCESS.

[!INFO]
Here is some INFO.


  1. Hello World! ↩︎

  2. Footnote ↩︎

P1004 [NOIP 2000 提高组] 方格取数

#走两次dp
如果只走一次,这题是非常经典的DP。但是要走两次,就变得非常有难度。
首先,可以简单地推广:要走两次,dp就存四个下标:

int[][][][] dp = new int[N][N][N][N];

我们只需要遍历所有可能,并且比较四种走法(同下、同右、一下一右),取最大值就可以了。
注意,一个数只能取一次,需要一个判断防止重复取数。

for (int i1 = 1; i1 < N; i1 += 1) {
for (int i2 = 1; i2 < N; i2 += 1) {
for (int j1 = 1; j1 < N; j1 += 1) {
for (int j2 = 1; j2 < N; j2 += 1) {
int step = map[i1][j1];
if (i2 != i1 && j2 != j1) step += map[i2][j2];

dp[i1][j1][i2][j2] =
Math.max(dp[i1-1][j1][i2-1][j2],
Math.max(dp[i1-1][j1][i2][j2-1],
Math.max(dp[i1][j1-1][i2-1][j2],
dp[i1][j1-1][i2][j2-1]))) + step;
}
}
}
}
System.out.println(dp[N-1][N-1][N-1][N-1]);

当然,4个循环时间复杂度太高了。我们可以用一个k == i1 + j1 == i2 + j2来减少一重循环。
这个k利用得很巧妙,因为每次要么向下走,要么向右走,所以k-1 == i-1 + j == i + j-1,全程使用k-1就能代表所有情况。

阅读全文 »

0.0 PTA实录

0.1.1 最大子列和plus

  • 如何利用语句先后顺序记录上一条信息pre_start_tag
void sum_max_sequence(void)
{
long long int this_sum, max_sum;
int start_tag, end_tag, pre_start_tag, neg_tag;

start_tag = pre_start_tag = end_tag = 0;
this_sum = max_sum = 0;
neg_tag = 1;

for (int i = 0; i < num; i++)
{
if (list[i] >= 0) {
neg_tag = 0;
}
this_sum += list[i];
if (this_sum > max_sum)
{
max_sum = this_sum;
end_tag = i;
pre_start_tag = start_tag; // 我没有想到的代码!
}
if (this_sum < 0)
{
this_sum = 0;
start_tag = i+1;
}
}


if(neg_tag) // 输出0,第一个和最后一个数
printf("%lld %d %d\n", max_sum, list[0], list[num-1]);
else if (max_sum == 0)
{
printf("0 0 0\n");
}

else
printf("%lld %d %d\n", max_sum, list[pre_start_tag], list[end_tag]);
}
阅读全文 »

51 和的逆运算

#全排列
这题在给定的和不重复的情况下很简单:

  1. 首先升序排序好数组sums,生成答案数组nums[n]
  2. nums[0] + nums[1] 必然等于sums[0](最小值),nums[0] + nums[2] 必然等于sums[1](次小值), … , nums[n-2] + nums[n-1] 必然等于sums[lastIndex](最大值)。
  3. 可以反向推测出nums[0] = (sums[0] + sums[1] - sums[n-1]) / 2,论证看下方:
nums[n] = {a, b, c, d, e} 从小到大排列
a + b = sums[0] (1) // 最小
a + c = sums[1] (2)
a + d = sums[2]
a + e = sums[3]
b + c = sums[4] (3)
...
(1) + (2) = 2a + (3)
2a = sums[0] + sums[1] - sums[n-1] = (1) + (2) - (3)
  1. 得出了nums[0],其他数字都可以用nums[i] = sums[i-1] - nums[0]推出来

但是给定的和重复的情况下,上面的第2条就不成立了。例如测试用例3:

阅读全文 »

Tomcat

JRE报错

一般教程会让我们配置JAVA_HOMEJRE_HOME,然后启动Tomcat;
然而,在JDK9以后,就不默认包含JRE了。
此时,我们使用命令

jlink --module-path jmods --add-modules java.desktop --output jre

生成一个JRE后,启动Tomcat,就会报错:

WARNING: Unknown module: java.rmi specified to --add-opens
Exception in thread "main" java.lang.NoClassDefFoundError: java/util/logging/Logger
at org.apache.juli.logging.DirectJDKLog.<init>(DirectJDKLog.java:61)
at org.apache.juli.logging.DirectJDKLog.getInstance(DirectJDKLog.java:181)
at org.apache.juli.logging.LogFactory.getInstance(LogFactory.java:133)
at org.apache.juli.logging.LogFactory.getInstance(LogFactory.java:156)
at org.apache.juli.logging.LogFactory.getLog(LogFactory.java:211)
at org.apache.catalina.startup.Bootstrap.<clinit>(Bootstrap.java:49)
Caused by: java.lang.ClassNotFoundException: java.util.logging.Logger
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525)
... 6 more

这时候,只需要把jre文件和JRE_HOME环境变量删除,Tomcat就能正常启动

阅读全文 »

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development"> <!-- 设置环境 -->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${驱动类(含包名)}"/>
<property name="url" value="${数据库连接URL}"/>
<property name="username" value="${用户名}"/>
<property name="password" value="${密码}"/>
</dataSource>
</environment>
</environments>
</configuration>

Util

一般只需要创建一次,所以创建一个工具类

public class MybatisUtil {

//在类加载时就进行创建
private static SqlSessionFactory sqlSessionFactory;
static {
try {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(new FileInputStream("mybatis-config.xml"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}

/**
* 获取一个新的会话
* @param autoCommit 是否开启自动提交(跟JDBC是一样的,如果不自动提交,则会变成事务操作)
* @return SqlSession对象
*/
public static SqlSession getSession(boolean autoCommit){
return sqlSessionFactory.openSession(autoCommit);
}
}
阅读全文 »

SpringBoot Mail 邮箱验证码

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
spring:
mail:
host: your.SMTP.host
username: your_server_email@email.com
password: your_passowrd
@Resource
JavaMailSender sender;

@PostMapping("/verification-email")
public String sendVerificationEmail(@RequestParam String targetEmail,
HttpSession session) {
SimpleMailMessage message = new SimpleMailMessage();
message.setSubject(EMAIL_TITLE);
int vCode = getVerificationCode();
session.setAttribute("vcode", vCode);
session.setAttribute("uemail", email);

message.setText(EMAIL_CONTEXT + code);
message.setTo(targetEmail);
message.setFrom(EMAIL_SERVEREMAIL); // 与配置文件中的保持一致

sender.send(message);
return "发送成功"; // 前端弹窗可以接受此参数
}

@PostMapping("/register")
public String register(@RequestParam String username,
@RequestParam String email,
@RequestParam String code,
@RequestParam String password,
HttpSession session) {
String sessionCode = session.getAttribute("vcode").toString;
String sessionEmail = session.getAttribute("uemail").toString;

if (sessionCode == null) {
return "验证码为空";
}
if (!sessionCode.equals(code)) {
return "验证码错误!";
}
if (!sessionEmail.equals(email)) {
return "请获取验证码";
}
}
阅读全文 »
0%