├── .gitattributes ├── .gitignore ├── .idea ├── artifacts │ ├── imagebed_war.xml │ └── imagebed_war_exploded.xml ├── compiler.xml ├── encodings.xml ├── libraries │ ├── Maven__ch_qos_logback_logback_classic_1_2_3.xml │ ├── Maven__ch_qos_logback_logback_core_1_2_3.xml │ ├── Maven__com_fasterxml_classmate_1_5_1.xml │ ├── Maven__com_fasterxml_jackson_core_jackson_annotations_2_10_2.xml │ ├── Maven__com_fasterxml_jackson_core_jackson_core_2_10_2.xml │ ├── Maven__com_fasterxml_jackson_core_jackson_databind_2_10_2.xml │ ├── Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_10_2.xml │ ├── Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_10_2.xml │ ├── Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_10_2.xml │ ├── Maven__jakarta_annotation_jakarta_annotation_api_1_3_5.xml │ ├── Maven__jakarta_validation_jakarta_validation_api_2_0_2.xml │ ├── Maven__org_apache_logging_log4j_log4j_api_2_12_1.xml │ ├── Maven__org_apache_logging_log4j_log4j_to_slf4j_2_12_1.xml │ ├── Maven__org_apache_tomcat_embed_tomcat_embed_core_9_0_30.xml │ ├── Maven__org_apache_tomcat_embed_tomcat_embed_el_9_0_30.xml │ ├── Maven__org_apache_tomcat_embed_tomcat_embed_websocket_9_0_30.xml │ ├── Maven__org_apache_tomcat_tomcat_servlet_api_8_0_36.xml │ ├── Maven__org_attoparser_attoparser_2_0_5_RELEASE.xml │ ├── Maven__org_hibernate_validator_hibernate_validator_6_0_18_Final.xml │ ├── Maven__org_jboss_logging_jboss_logging_3_4_1_Final.xml │ ├── Maven__org_slf4j_jul_to_slf4j_1_7_30.xml │ ├── Maven__org_slf4j_slf4j_api_1_7_30.xml │ ├── Maven__org_springframework_boot_spring_boot_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_autoconfigure_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_devtools_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_json_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_logging_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_thymeleaf_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_tomcat_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_validation_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_web_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_spring_aop_5_2_3_RELEASE.xml │ ├── Maven__org_springframework_spring_beans_5_2_3_RELEASE.xml │ ├── Maven__org_springframework_spring_context_5_2_3_RELEASE.xml │ ├── Maven__org_springframework_spring_core_5_2_3_RELEASE.xml │ ├── Maven__org_springframework_spring_expression_5_2_3_RELEASE.xml │ ├── Maven__org_springframework_spring_jcl_5_2_3_RELEASE.xml │ ├── Maven__org_springframework_spring_web_5_2_3_RELEASE.xml │ ├── Maven__org_springframework_spring_webmvc_5_2_3_RELEASE.xml │ ├── Maven__org_thymeleaf_extras_thymeleaf_extras_java8time_3_0_4_RELEASE.xml │ ├── Maven__org_thymeleaf_thymeleaf_3_0_11_RELEASE.xml │ ├── Maven__org_thymeleaf_thymeleaf_spring5_3_0_11_RELEASE.xml │ ├── Maven__org_unbescape_unbescape_1_1_6_RELEASE.xml │ └── Maven__org_yaml_snakeyaml_1_25.xml ├── misc.xml ├── modules.xml ├── uiDesigner.xml ├── vcs.xml └── workspace.xml ├── .mvn └── wrapper │ ├── MavenWrapperDownloader.java │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── README.md ├── config.ini ├── imagebed.iml ├── license ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── paster │ │ ├── Application.java │ │ ├── ImageBedApplication.java │ │ ├── bean │ │ ├── History.java │ │ └── Pic.java │ │ ├── controller │ │ ├── MainController.java │ │ ├── UploadController.java │ │ ├── admin │ │ │ ├── Admin.java │ │ │ └── api │ │ │ │ ├── AdminAction.java │ │ │ │ └── ConfigAction.java │ │ └── api │ │ │ └── HistoryApi.java │ │ ├── log │ │ └── Logger.java │ │ ├── prop │ │ └── Prop.java │ │ └── utlis │ │ ├── FileUtils.java │ │ ├── HistoryTools.java │ │ ├── IPUtils.java │ │ └── LittleTools.java └── resources │ ├── application.properties │ ├── static │ ├── add.png │ ├── bootstrap │ │ └── bootstrap.min.css │ ├── close.png │ ├── css │ │ ├── admin │ │ │ └── admin.css │ │ ├── bs4.pop.css │ │ ├── history │ │ │ └── style.css │ │ ├── main.css │ │ ├── mobile.css │ │ └── show.css │ ├── doge.png │ ├── favicon.ico │ └── js │ │ ├── admin │ │ └── admin.js │ │ ├── axios.min.js │ │ ├── bs4.pop.js │ │ ├── click.js │ │ ├── go.js │ │ ├── history │ │ ├── func.js │ │ └── modernizr.js │ │ ├── jquery.lazyload.js │ │ ├── jquery.min.js │ │ └── main.js │ └── templates │ ├── admin.html │ ├── history.html │ └── index.html └── test └── java └── paster └── imagebed └── Test.java /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-language=Java 2 | *.css linguist-language=Java 3 | *.html linguist-language=Java 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/* 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /.idea/artifacts/imagebed_war.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/target 4 | 5 | 6 | imagebed 7 | war 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/artifacts/imagebed_war_exploded.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/target/imagebed-0.0.1-SNAPSHOT 4 | 5 | 6 | true 7 | imagebed 8 | war 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__ch_qos_logback_logback_core_1_2_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_classmate_1_5_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_10_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_10_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_10_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_10_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_10_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_10_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__jakarta_annotation_jakarta_annotation_api_1_3_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__jakarta_validation_jakarta_validation_api_2_0_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_12_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_12_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_9_0_30.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_el_9_0_30.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_9_0_30.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_tomcat_tomcat_servlet_api_8_0_36.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_attoparser_attoparser_2_0_5_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_hibernate_validator_hibernate_validator_6_0_18_Final.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_jboss_logging_jboss_logging_3_4_1_Final.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_30.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_30.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_devtools_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_json_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_thymeleaf_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_validation_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_aop_5_2_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_beans_5_2_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_context_5_2_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_core_5_2_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_expression_5_2_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_jcl_5_2_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_web_5_2_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_webmvc_5_2_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_thymeleaf_extras_thymeleaf_extras_java8time_3_0_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_thymeleaf_thymeleaf_3_0_11_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_thymeleaf_thymeleaf_spring5_3_0_11_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_unbescape_unbescape_1_1_6_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_yaml_snakeyaml_1_25.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 1581304358860 143 | 144 | 145 | 1581304358860 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 1672919853062 237 | 238 | 239 | 240 | 1672919853062 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | paster.imagebed.* 279 | 280 | 281 | -------------------------------------------------------------------------------- /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007-present the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import java.net.*; 18 | import java.io.*; 19 | import java.nio.channels.*; 20 | import java.util.Properties; 21 | 22 | public class MavenWrapperDownloader { 23 | 24 | private static final String WRAPPER_VERSION = "0.5.6"; 25 | /** 26 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 27 | */ 28 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 29 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 30 | 31 | /** 32 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 33 | * use instead of the default one. 34 | */ 35 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 36 | ".mvn/wrapper/maven-wrapper.properties"; 37 | 38 | /** 39 | * Path where the maven-wrapper.jar will be saved to. 40 | */ 41 | private static final String MAVEN_WRAPPER_JAR_PATH = 42 | ".mvn/wrapper/maven-wrapper.jar"; 43 | 44 | /** 45 | * Name of the property which should be used to override the default download url for the wrapper. 46 | */ 47 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 48 | 49 | public static void main(String args[]) { 50 | System.out.println("- Downloader started"); 51 | File baseDirectory = new File(args[0]); 52 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 53 | 54 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 55 | // wrapperUrl parameter. 56 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 57 | String url = DEFAULT_DOWNLOAD_URL; 58 | if (mavenWrapperPropertyFile.exists()) { 59 | FileInputStream mavenWrapperPropertyFileInputStream = null; 60 | try { 61 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 62 | Properties mavenWrapperProperties = new Properties(); 63 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 64 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 65 | } catch (IOException e) { 66 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 67 | } finally { 68 | try { 69 | if (mavenWrapperPropertyFileInputStream != null) { 70 | mavenWrapperPropertyFileInputStream.close(); 71 | } 72 | } catch (IOException e) { 73 | // Ignore ... 74 | } 75 | } 76 | } 77 | System.out.println("- Downloading from: " + url); 78 | 79 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 80 | if (!outputFile.getParentFile().exists()) { 81 | if (!outputFile.getParentFile().mkdirs()) { 82 | System.out.println( 83 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 84 | } 85 | } 86 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 87 | try { 88 | downloadFileFromURL(url, outputFile); 89 | System.out.println("Done"); 90 | System.exit(0); 91 | } catch (Throwable e) { 92 | System.out.println("- Error downloading"); 93 | e.printStackTrace(); 94 | System.exit(1); 95 | } 96 | } 97 | 98 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 99 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 100 | String username = System.getenv("MVNW_USERNAME"); 101 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 102 | Authenticator.setDefault(new Authenticator() { 103 | @Override 104 | protected PasswordAuthentication getPasswordAuthentication() { 105 | return new PasswordAuthentication(username, password); 106 | } 107 | }); 108 | } 109 | URL website = new URL(urlString); 110 | ReadableByteChannel rbc; 111 | rbc = Channels.newChannel(website.openStream()); 112 | FileOutputStream fos = new FileOutputStream(destination); 113 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 114 | fos.close(); 115 | rbc.close(); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Programming-With-Love/PingeBed/f0f705cee5fe85fd8bf8fa578f01f5fdf59b9c0d/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # :star: PingeBed 2 | 3 | :black_nib:真· 本地图床,使用SpringBoot开发,面向用户的网络图床服务。 4 | :joy: 开发时长两年半的个人图床 5 | 6 | # 实现 7 | 用户在品格图床中上传图片文件(`jpg`/`jpeg`/`png`/`svg`/`gif`/`bmp`/`ico`/`tiff`),图床会自动把图片上传到程序的`运行目录`中 8 | 9 | PingeBed会把用户上传的图片保存到`本地`,而不是公共容器中。 10 | 11 | 我们提供了两个API让用户可以获取自己的历史记录,这样就不用进入/history页面了(虽然我感觉/history页面很好看:cry:) 12 | /api/getIp:获取用户的IP地址,为查询历史记录做准备 13 | /api/getPics?ip=*: 通过IP地址查询历史记录 14 | 历史记录通过建立一个文件的方式存储 15 |  16 | 样式 序号=原文件名:/年/日/随机生成的文件名 17 |  18 | 19 | # :books: 功能 20 | 21 | - [x] 自动生成图片对应的`URL格式链接`、`HTML标签格式链接`、`Markdown格式链接` 22 | 23 | - [x] 图片链接克隆(转存)功能,可输入图片的URL,图床会自动下载并保存到图床服务器中 24 | 25 | - [x] 历史记录功能(按IP地址读取,所以更换IP地址后无法查询) 26 | 27 | - [x] 图床管理员后台设置界面(基于配置文件存储,不依赖数据库) 28 | 29 | - [x] 仅管理员可上传功能(默认关闭,必须在后台管理员登录后才能上传) 30 | 31 | # :underage: 技术使用 32 | #### 前端: 33 | Jquery 34 | Bootstrap 35 | Axios 36 | #### 后端 37 | Thymeleaf 38 | Spring Boot 39 | #### 开发工具 40 | IDEA 41 | 42 | # :mag: 展示 43 | ## 上传 44 |  45 | ## 历史记录 46 | 47 | 有时间描述,更加清晰 48 | 49 |  50 | ## 管理 51 |  52 | 53 | ## 整体 54 | gif可能会加载不出来,还是clone一个看看吧 55 |  56 | 57 | # :clipboard: 使用方法 58 | 因为是本地图床,所以不需要配置数据库。如果是使用IDEA运行或者是使用maven打包成war包,图床会自动在项目根目录下创建uploadImages文件夹,并把上传的文件保存在此文件夹内。你可以在FileUtils.java中找到此代码: 59 | 60 | ``` 61 | String path = ClassUtils.getDefaultClassLoader().getResource("").getPath() + "static/uploadImages/"; 62 | ``` 63 | 64 | 因为项目使用了Thymeleaf,所以static是存储了静态资源的根目录。 65 | ### 打包War 包: 66 | 67 | * 品格图床可以在Tomcat中运行 68 | * 如果你想自己修改品格图床的源码,Clone后在Intellij IDEA中运行,使用Maven - package打包新的war包,新的war包位置在一般在`target`目录中。如图所示: 69 |  70 | 71 | ### :heavy_plus_sign:修改上传文件大小限制 72 | 73 | 你可以在application.properties文件里修改配置 74 | 75 | ``` 76 | //上传文件大小 77 | spring.servlet.multipart.max-file-size=30MB 78 | //最大请求大小 79 | spring.servlet.multipart.max-request-size=30MB 80 | ``` 81 | 用户会在前端页面看到文件上传限制 82 | ### :no_entry_sign: 注意事项 83 | 如果你使用了Tomcat 或 Tomcat和Nginx搭载了Picuang,你可能会遇到上传失败的情况。请按照下方的几个解决办法尝试: 84 | 85 | 1. Tomcat:context.xml 86 | 87 | 修改`conf/context.xml`文件,在``之前添加一行: 88 | 89 | ``` 90 | 91 | ``` 92 | 93 | 2. Tomcat:server.xml 94 | 95 | 修改`conf/server.xml`文件,在你使用端口的`Connector`配置中添加一条: 96 | 97 | ``` 98 | maxPostSize="209715200" 99 | ``` 100 | 101 | 3. Nginx 102 | 103 | 在你的`location / {`下添加一行: 104 | 105 | ``` 106 | client_max_body_size 100m;` 107 | ``` 108 | 109 | # :heart: Thanks 110 | 111 | 感谢[AdlerED](https://github.com/AdlerED)大佬对我的帮助, [必床](https://pic.stackoverflow.wiki/) ,这是他的开源图床项目,我也是受了他的启发才做出了这个项目,所以有很多地方上都有异曲同工之处 112 | 113 | # :mailbox_with_mail: 114 | 因为个人水平和开发时间原因,所以这个图床项目可能还存在一些bug,如果你发现了bug或者是有一些好的建议可以选择加微信(zq2011001421)和邮箱(zlyszzq@163.com)二选一的方式告诉我。 115 | -------------------------------------------------------------------------------- /config.ini: -------------------------------------------------------------------------------- 1 | #Save Config File 2 | #Sat Jan 07 10:53:27 CST 2023 3 | version=1.1 4 | password=123456 5 | size=150.46 6 | imageUploadCount=1 7 | anonymous=true 8 | -------------------------------------------------------------------------------- /imagebed.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 teahouse15 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Mingw, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | fi 118 | 119 | if [ -z "$JAVA_HOME" ]; then 120 | javaExecutable="`which javac`" 121 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 122 | # readlink(1) is not available as standard on Solaris 10. 123 | readLink=`which readlink` 124 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 125 | if $darwin ; then 126 | javaHome="`dirname \"$javaExecutable\"`" 127 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 128 | else 129 | javaExecutable="`readlink -f \"$javaExecutable\"`" 130 | fi 131 | javaHome="`dirname \"$javaExecutable\"`" 132 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 133 | JAVA_HOME="$javaHome" 134 | export JAVA_HOME 135 | fi 136 | fi 137 | fi 138 | 139 | if [ -z "$JAVACMD" ] ; then 140 | if [ -n "$JAVA_HOME" ] ; then 141 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 142 | # IBM's JDK on AIX uses strange locations for the executables 143 | JAVACMD="$JAVA_HOME/jre/sh/java" 144 | else 145 | JAVACMD="$JAVA_HOME/bin/java" 146 | fi 147 | else 148 | JAVACMD="`which java`" 149 | fi 150 | fi 151 | 152 | if [ ! -x "$JAVACMD" ] ; then 153 | echo "Error: JAVA_HOME is not defined correctly." >&2 154 | echo " We cannot execute $JAVACMD" >&2 155 | exit 1 156 | fi 157 | 158 | if [ -z "$JAVA_HOME" ] ; then 159 | echo "Warning: JAVA_HOME environment variable is not set." 160 | fi 161 | 162 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 163 | 164 | # traverses directory structure from process work directory to filesystem root 165 | # first directory with .mvn subdirectory is considered project base directory 166 | find_maven_basedir() { 167 | 168 | if [ -z "$1" ] 169 | then 170 | echo "Path not specified to find_maven_basedir" 171 | return 1 172 | fi 173 | 174 | basedir="$1" 175 | wdir="$1" 176 | while [ "$wdir" != '/' ] ; do 177 | if [ -d "$wdir"/.mvn ] ; then 178 | basedir=$wdir 179 | break 180 | fi 181 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 182 | if [ -d "${wdir}" ]; then 183 | wdir=`cd "$wdir/.."; pwd` 184 | fi 185 | # end of workaround 186 | done 187 | echo "${basedir}" 188 | } 189 | 190 | # concatenates all lines of a file 191 | concat_lines() { 192 | if [ -f "$1" ]; then 193 | echo "$(tr -s '\n' ' ' < "$1")" 194 | fi 195 | } 196 | 197 | BASE_DIR=`find_maven_basedir "$(pwd)"` 198 | if [ -z "$BASE_DIR" ]; then 199 | exit 1; 200 | fi 201 | 202 | ########################################################################################## 203 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 204 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 205 | ########################################################################################## 206 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 207 | if [ "$MVNW_VERBOSE" = true ]; then 208 | echo "Found .mvn/wrapper/maven-wrapper.jar" 209 | fi 210 | else 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 213 | fi 214 | if [ -n "$MVNW_REPOURL" ]; then 215 | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 216 | else 217 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 218 | fi 219 | while IFS="=" read key value; do 220 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 221 | esac 222 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 223 | if [ "$MVNW_VERBOSE" = true ]; then 224 | echo "Downloading from: $jarUrl" 225 | fi 226 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 227 | if $cygwin; then 228 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 229 | fi 230 | 231 | if command -v wget > /dev/null; then 232 | if [ "$MVNW_VERBOSE" = true ]; then 233 | echo "Found wget ... using wget" 234 | fi 235 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 236 | wget "$jarUrl" -O "$wrapperJarPath" 237 | else 238 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" 239 | fi 240 | elif command -v curl > /dev/null; then 241 | if [ "$MVNW_VERBOSE" = true ]; then 242 | echo "Found curl ... using curl" 243 | fi 244 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 245 | curl -o "$wrapperJarPath" "$jarUrl" -f 246 | else 247 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 248 | fi 249 | 250 | else 251 | if [ "$MVNW_VERBOSE" = true ]; then 252 | echo "Falling back to using Java to download" 253 | fi 254 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 255 | # For Cygwin, switch paths to Windows format before running javac 256 | if $cygwin; then 257 | javaClass=`cygpath --path --windows "$javaClass"` 258 | fi 259 | if [ -e "$javaClass" ]; then 260 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 261 | if [ "$MVNW_VERBOSE" = true ]; then 262 | echo " - Compiling MavenWrapperDownloader.java ..." 263 | fi 264 | # Compiling the Java class 265 | ("$JAVA_HOME/bin/javac" "$javaClass") 266 | fi 267 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 268 | # Running the downloader 269 | if [ "$MVNW_VERBOSE" = true ]; then 270 | echo " - Running MavenWrapperDownloader.java ..." 271 | fi 272 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 273 | fi 274 | fi 275 | fi 276 | fi 277 | ########################################################################################## 278 | # End of extension 279 | ########################################################################################## 280 | 281 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 282 | if [ "$MVNW_VERBOSE" = true ]; then 283 | echo $MAVEN_PROJECTBASEDIR 284 | fi 285 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 286 | 287 | # For Cygwin, switch paths to Windows format before running java 288 | if $cygwin; then 289 | [ -n "$M2_HOME" ] && 290 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 291 | [ -n "$JAVA_HOME" ] && 292 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 293 | [ -n "$CLASSPATH" ] && 294 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 295 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 296 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 297 | fi 298 | 299 | # Provide a "standardized" way to retrieve the CLI args that will 300 | # work with both Windows and non-Windows executions. 301 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 302 | export MAVEN_CMD_LINE_ARGS 303 | 304 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 305 | 306 | exec "$JAVACMD" \ 307 | $MAVEN_OPTS \ 308 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 309 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 310 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 311 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 124 | 125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 162 | if ERRORLEVEL 1 goto error 163 | goto end 164 | 165 | :error 166 | set ERROR_CODE=1 167 | 168 | :end 169 | @endlocal & set ERROR_CODE=%ERROR_CODE% 170 | 171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 175 | :skipRcPost 176 | 177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 179 | 180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 181 | 182 | exit /B %ERROR_CODE% 183 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.4.RELEASE 9 | 10 | 11 | war 12 | paster 13 | imagebed 14 | 0.0.1-SNAPSHOT 15 | imagebed 16 | 练习图床----不许放弃!!!!! 17 | 18 | 19 | 1.8 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-devtools 26 | true 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-thymeleaf 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-web 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | org.apache.tomcat 46 | tomcat-servlet-api 47 | 8.0.36 48 | provided 49 | 50 | 51 | 52 | 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-maven-plugin 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/main/java/paster/Application.java: -------------------------------------------------------------------------------- 1 | package paster; 2 | 3 | import org.springframework.boot.builder.SpringApplicationBuilder; 4 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 5 | 6 | public class Application extends SpringBootServletInitializer { 7 | @Override 8 | protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) { 9 | return builder.sources(ImageBedApplication.class); 10 | } 11 | } -------------------------------------------------------------------------------- /src/main/java/paster/ImageBedApplication.java: -------------------------------------------------------------------------------- 1 | package paster; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.builder.SpringApplicationBuilder; 6 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 7 | import paster.prop.Prop; 8 | 9 | @SpringBootApplication 10 | public class ImageBedApplication { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(ImageBedApplication.class, args); 14 | Prop.init(); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/paster/bean/History.java: -------------------------------------------------------------------------------- 1 | package paster.bean; 2 | 3 | 4 | import paster.utlis.HistoryTools; 5 | 6 | import java.io.*; 7 | import java.util.Properties; 8 | 9 | public class History { 10 | 11 | Properties properties; 12 | 13 | // 地址 14 | String url; 15 | 16 | // 上传图片数量 17 | int count = 0; 18 | 19 | // 获取History文件的FileOutputStream对象 20 | FileOutputStream fileOutputStream; 21 | 22 | FileInputStream fileInputStream; 23 | 24 | public History(String url) { 25 | this.url = url; 26 | try { 27 | File history = null; 28 | if (!HistoryTools.historyExist()) { 29 | history = new File("history/"); 30 | history.mkdir(); 31 | } 32 | if (url.contains(":")) { 33 | url = url.replace(":", "."); 34 | } 35 | this.fileOutputStream = new FileOutputStream("history/" + url + ".txt", true); 36 | this.fileInputStream = new FileInputStream("history/" + url + ".txt"); 37 | this.properties = new Properties(); 38 | this.properties.load(fileInputStream); 39 | } catch (FileNotFoundException e) { 40 | e.printStackTrace(); 41 | } catch (IOException e) { 42 | e.printStackTrace(); 43 | } 44 | } 45 | 46 | public int getCount() { 47 | return count; 48 | } 49 | 50 | public FileInputStream getFileInputStream() { 51 | return fileInputStream; 52 | } 53 | 54 | public void setFileInputStream(FileInputStream fileInputStream) { 55 | this.fileInputStream = fileInputStream; 56 | } 57 | 58 | public FileOutputStream getFileOutputStream() { 59 | return fileOutputStream; 60 | } 61 | 62 | public void setFileOutputStream(FileOutputStream fileOutputStream) { 63 | this.fileOutputStream = fileOutputStream; 64 | } 65 | 66 | public void setCount(int count) { 67 | this.count = count; 68 | } 69 | 70 | public String getUrl() { 71 | return url; 72 | } 73 | 74 | public void setUrl(String url) { 75 | this.url = url; 76 | } 77 | 78 | public Properties getProperties() { 79 | return properties; 80 | } 81 | 82 | public void setProperties(Properties properties) { 83 | this.properties = properties; 84 | } 85 | } -------------------------------------------------------------------------------- /src/main/java/paster/bean/Pic.java: -------------------------------------------------------------------------------- 1 | package paster.bean; 2 | 3 | public class Pic { 4 | 5 | String filename; 6 | String path; 7 | String ip; 8 | 9 | public void setFilename(String filename) { 10 | this.filename = filename; 11 | } 12 | 13 | public String getFilename() { 14 | return filename; 15 | } 16 | 17 | public void setIp(String ip) { 18 | this.ip = ip; 19 | } 20 | 21 | public String getIp() { 22 | return ip; 23 | } 24 | 25 | public void setPath(String path) { 26 | this.path = path; 27 | } 28 | 29 | public String getPath() { 30 | return path; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/paster/controller/MainController.java: -------------------------------------------------------------------------------- 1 | package paster.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.servlet.ModelAndView; 7 | import paster.bean.History; 8 | import paster.prop.Prop; 9 | import paster.utlis.HistoryTools; 10 | import paster.utlis.IPUtils; 11 | 12 | import javax.servlet.http.HttpServletRequest; 13 | 14 | @Controller 15 | public class MainController { 16 | 17 | @Value("${spring.servlet.multipart.max-file-size}") 18 | private String size; 19 | 20 | @RequestMapping(value = "/") 21 | public ModelAndView main(HttpServletRequest request) { 22 | ModelAndView modelAndView = new ModelAndView("/index"); 23 | modelAndView.addObject("uploadSize", size); 24 | modelAndView.addObject("uploadImageCount", Prop.getProperty( "imageUploadCount")); 25 | modelAndView.addObject("freeSize", Prop.getProperty("size")); 26 | return modelAndView; 27 | } 28 | 29 | 30 | @RequestMapping(value = "/history") 31 | public ModelAndView history(HttpServletRequest request) { 32 | ModelAndView modelAndView = new ModelAndView("/history"); 33 | String ip = IPUtils.getIpAddress(request); 34 | modelAndView.addObject("ip", ip); 35 | return modelAndView; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/paster/controller/UploadController.java: -------------------------------------------------------------------------------- 1 | package paster.controller; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.util.ClassUtils; 5 | import org.springframework.web.bind.annotation.*; 6 | import org.springframework.web.multipart.MultipartFile; 7 | import paster.log.Logger; 8 | import paster.prop.Prop; 9 | import paster.utlis.FileUtils; 10 | import paster.utlis.IPUtils; 11 | 12 | import javax.servlet.http.HttpServletRequest; 13 | import java.util.Map; 14 | import java.util.TreeMap; 15 | 16 | 17 | @Controller 18 | public class UploadController { 19 | 20 | public static boolean anonymous = true; 21 | 22 | @RequestMapping(value = "/upload", method = RequestMethod.POST) 23 | @ResponseBody 24 | public Map upload(MultipartFile file, HttpServletRequest request) { 25 | anonymous = Boolean.parseBoolean(Prop.getProperty("anonymous")); 26 | if (anonymous) { 27 | String address = IPUtils.getIpAddress(request); 28 | Logger.log(Logger.INFO, "地址: " + address + "上传了文件 " + file.getOriginalFilename()); 29 | return FileUtils.saveFile(file, address); 30 | } 31 | Map map = new TreeMap(); 32 | map.put("state", "!admin"); 33 | map.put("msg", "管理员禁止了匿名用户上传文件"); 34 | return map; 35 | } 36 | 37 | 38 | @RequestMapping(value = "/clone", method = RequestMethod.POST) 39 | @ResponseBody 40 | public Map clone(@RequestBody Map map, HttpServletRequest request) { 41 | anonymous = Boolean.parseBoolean(Prop.getProperty("anonymous")); 42 | if (anonymous) { 43 | // 获取要克隆的网址 44 | String url = (String) map.get("url"); 45 | return FileUtils.cloneFile(url, IPUtils.getIpAddress(request)); 46 | } 47 | Map map2 = new TreeMap(); 48 | map2.put("state", "!admin"); 49 | map2.put("msg", "管理员禁止了匿名用户上传文件"); 50 | 51 | return map2; 52 | 53 | } 54 | } -------------------------------------------------------------------------------- /src/main/java/paster/controller/admin/Admin.java: -------------------------------------------------------------------------------- 1 | package paster.controller.admin; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.servlet.ModelAndView; 6 | 7 | @Controller 8 | public class Admin { 9 | 10 | @RequestMapping("/admin") 11 | public ModelAndView admin() { 12 | ModelAndView modelAndView = new ModelAndView("/admin"); 13 | return modelAndView; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/paster/controller/admin/api/AdminAction.java: -------------------------------------------------------------------------------- 1 | package paster.controller.admin.api; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.ResponseBody; 6 | import paster.prop.Prop; 7 | 8 | import javax.servlet.http.HttpSession; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.TreeMap; 13 | 14 | @Controller 15 | public class AdminAction { 16 | 17 | @RequestMapping("/api/isLogin") 18 | @ResponseBody 19 | public static boolean isLogin(HttpSession session) { 20 | Boolean logged; 21 | try { 22 | logged = Boolean.valueOf(session.getAttribute("login").toString()); 23 | if (logged) { 24 | return true; 25 | } else { 26 | return false; 27 | } 28 | } catch (NullPointerException e) { 29 | return false; 30 | } 31 | // Boolean logged = Boolean.valueOf(session.getAttribute("login").toString()); 32 | } 33 | 34 | public void logOut(HttpSession session) { 35 | session.setAttribute("login", false); 36 | } 37 | 38 | @RequestMapping("/api/login") 39 | @ResponseBody 40 | public Map login(HttpSession session, String password) { 41 | Map map = new TreeMap(); 42 | String pwd = Prop.getProperty("password"); 43 | if (!pwd.equals(password)) { 44 | map.put("msg", "fail"); 45 | return map; 46 | } 47 | session.setAttribute("login", true); 48 | List conf = new ArrayList<>(); 49 | conf.add(Prop.getProperty("anonymous")); 50 | conf.add(Prop.getProperty("imageUploadCount")); 51 | conf.add(Prop.getProperty("size")); 52 | conf.add(Prop.getProperty("password")); 53 | conf.add(Prop.getProperty("version")); 54 | 55 | map.put("msg", "success"); 56 | map.put("data", conf); 57 | 58 | return map; 59 | } 60 | 61 | 62 | @RequestMapping("/api/logout") 63 | @ResponseBody 64 | public Map logout(HttpSession session) { 65 | Map map = new TreeMap(); 66 | 67 | if (isLogin(session)) { 68 | logOut(session); 69 | map.put("msg", "success"); 70 | 71 | return map; 72 | } 73 | 74 | map.put("msg", "fail"); 75 | return map; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/paster/controller/admin/api/ConfigAction.java: -------------------------------------------------------------------------------- 1 | package paster.controller.admin.api; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.ResponseBody; 6 | import paster.prop.Prop; 7 | 8 | import javax.servlet.http.HttpSession; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | @Controller 13 | public class ConfigAction { 14 | 15 | @RequestMapping("/api/getConf") 16 | @ResponseBody 17 | public Map getConf(HttpSession session, String conf) { 18 | Map map = new HashMap(); 19 | if (!AdminAction.isLogin(session)) { 20 | map.put("msg", "fail"); 21 | return map; 22 | } 23 | String msg = Prop.getProperty(conf); 24 | 25 | map.put("msg", "success"); 26 | map.put("conf", conf); 27 | map.put("value", msg); 28 | return map; 29 | } 30 | 31 | @RequestMapping("/api/setConf") 32 | @ResponseBody 33 | public Map setConf(HttpSession session, String key, String value) { 34 | Map map = new HashMap(); 35 | if (!AdminAction.isLogin(session)) { 36 | map.put("msg", "fail"); 37 | return map; 38 | } 39 | Prop.modify(key, value); 40 | 41 | map.put("msg", "success"); 42 | map.put(key, value); 43 | return map; 44 | } 45 | 46 | @RequestMapping("/api/reload") 47 | @ResponseBody 48 | public Map reload(HttpSession session) { 49 | Map map = new HashMap(); 50 | 51 | if (!AdminAction.isLogin(session)) { 52 | map.put("msg", "fail"); 53 | return map; 54 | } 55 | Prop.reload(); 56 | map.put("msg", "success"); 57 | return map; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/paster/controller/api/HistoryApi.java: -------------------------------------------------------------------------------- 1 | package paster.controller.api; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.ResponseBody; 6 | import paster.bean.History; 7 | import paster.bean.Pic; 8 | import paster.utlis.HistoryTools; 9 | import paster.utlis.IPUtils; 10 | 11 | import javax.servlet.http.HttpServletRequest; 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | import java.util.Map; 15 | import java.util.TreeMap; 16 | 17 | @Controller 18 | public class HistoryApi { 19 | 20 | @RequestMapping("/api/getpic") 21 | @ResponseBody 22 | public Pic getMsg(HttpServletRequest request, int id) { 23 | String address = IPUtils.getIpAddress(request); 24 | History history = HistoryTools.getHistory(address); 25 | Pic pic = new Pic(); 26 | pic.setFilename(HistoryTools.getRecord(history, id-1).split(":")[1].split("/")[3]); 27 | pic.setIp(address); 28 | pic.setPath(HistoryTools.getRecord(history, id-1).split(":")[1]); 29 | 30 | return pic; 31 | } 32 | 33 | @RequestMapping("/api/getAllPics") 34 | @ResponseBody 35 | public Map allPics(HttpServletRequest request) { 36 | Map map = new TreeMap(); 37 | String ip = IPUtils.getIpAddress(request); 38 | History history = HistoryTools.getHistory(ip); 39 | List list = new ArrayList(); 40 | if (history == null) { 41 | map.put("msg", "fail"); 42 | map.put("data", ip); 43 | return map; 44 | } 45 | for (String s : HistoryTools.allImg(history)) { 46 | Pic pic = new Pic(); 47 | pic.setFilename(s.split("/")[3]); 48 | pic.setIp(ip); 49 | pic.setPath(s); 50 | list.add(pic); 51 | } 52 | map.put("msg", "success"); 53 | map.put("data", list); 54 | return map; 55 | } 56 | 57 | @RequestMapping("/api/getAllApi") 58 | @ResponseBody 59 | public Map getAllApi() { 60 | Map map = new TreeMap(); 61 | map.put("0", "/api/getConf?conf=*"); 62 | map.put("1", "/api/setConf?key=*&value=*"); 63 | map.put("2", "/api/getpic?id=*"); 64 | map.put("3", "/api/getAllPics"); 65 | map.put("4", "/api/login?password=*"); 66 | map.put("5", "/api/reload"); 67 | map.put("6", "/api/logout"); 68 | map.put("7", "/api/isLogin"); 69 | map.put("8", "/api/getIp"); 70 | map.put("9", "/api/getPics"); 71 | 72 | return map; 73 | } 74 | 75 | @RequestMapping("/api/getIp") 76 | @ResponseBody 77 | public Map getIp(HttpServletRequest request) { 78 | Map map = new TreeMap(); 79 | map.put("ip", IPUtils.getIpAddress(request)); 80 | return map; 81 | } 82 | 83 | @RequestMapping("/api/getPics") 84 | @ResponseBody 85 | public Map getPics(HttpServletRequest request, String ip) { 86 | Map map = new TreeMap(); 87 | History history = HistoryTools.getHistory(ip); 88 | List list = new ArrayList(); 89 | if (history == null) { 90 | map.put("msg", "fail"); 91 | map.put("data", ip); 92 | return map; 93 | } 94 | for (String s : HistoryTools.allImg(history)) { 95 | Pic pic = new Pic(); 96 | pic.setFilename(s.split("/")[3]); 97 | pic.setIp(ip); 98 | pic.setPath(s); 99 | 100 | list.add(pic); 101 | } 102 | map.put("", "success"); 103 | map.put("data", list); 104 | 105 | 106 | return map; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/paster/log/Logger.java: -------------------------------------------------------------------------------- 1 | package paster.log; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | public class Logger { 7 | static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 8 | 9 | public static final String WARN = "WARN"; 10 | 11 | public static final String DEBUG = "DEBUG"; 12 | 13 | public static final String INFO = "INFO"; 14 | 15 | public static void log(String level, String msg) { 16 | System.out.println("[ImgBed][" + level +"][" + simpleDateFormat.format(new Date()) + "] " + msg); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/paster/prop/Prop.java: -------------------------------------------------------------------------------- 1 | package paster.prop; 2 | 3 | import paster.log.Logger; 4 | import paster.utlis.LittleTools; 5 | 6 | import java.io.*; 7 | import java.util.Properties; 8 | 9 | public class Prop { 10 | 11 | private static Properties properties = null; 12 | 13 | /** 14 | * 初始化配置文件 15 | */ 16 | public static void init() { 17 | // 没有配置文件 18 | if (!new File(System.getProperty("user.dir") + "/config.ini").exists()) { 19 | properties = new Properties(); 20 | Logger.log(Logger.INFO,"[Prop] init Properties"); 21 | properties.setProperty("password", "123456"); 22 | properties.setProperty("size", LittleTools.freeSize()); 23 | properties.setProperty("anonymous", "true"); 24 | properties.setProperty("imageUploadCount", "0"); 25 | properties.setProperty("version", "1.1"); 26 | save(); 27 | return; 28 | } 29 | 30 | // 有配置文件 31 | try { 32 | properties = new Properties(); 33 | properties.load(new FileReader(System.getProperty("user.dir") + "/config.ini")); 34 | Logger.log(Logger.INFO,"[Prop] properties haven loaded"); 35 | } catch (IOException e) { 36 | e.printStackTrace(); 37 | } 38 | } 39 | 40 | /** 41 | * 保存配置 42 | */ 43 | public static void save() { 44 | try { 45 | FileOutputStream config = new FileOutputStream(System.getProperty("user.dir") + "/config.ini"); 46 | properties.store(config, "Save Config File"); 47 | Logger.log(Logger.INFO,"[Prop] Saved the Properties"); 48 | } catch (IOException e) { 49 | e.printStackTrace(); 50 | } 51 | } 52 | 53 | 54 | public static void modify(String key, String value) { 55 | properties.setProperty(key, value); 56 | Logger.log(Logger.INFO,"[Prop] Modify " + key + "=" + value); 57 | save(); 58 | } 59 | 60 | public static void modify(String key, int value) { 61 | properties.setProperty(key, String.valueOf(value)); 62 | Logger.log(Logger.INFO,"[Prop] Modify " + key + "=" + value); 63 | save(); 64 | } 65 | 66 | public static String getProperty(String key) { 67 | return properties.getProperty(key); 68 | } 69 | 70 | public static void reload() { 71 | properties.setProperty("password", "123456"); 72 | properties.setProperty("size", LittleTools.freeSize()); 73 | properties.setProperty("anonymous", "on"); 74 | properties.setProperty("imageUploadCount", "0"); 75 | properties.setProperty("version", "1.1"); 76 | 77 | Logger.log(Logger.INFO,"[Prop] Properties Reload"); 78 | } 79 | } -------------------------------------------------------------------------------- /src/main/java/paster/utlis/FileUtils.java: -------------------------------------------------------------------------------- 1 | package paster.utlis; 2 | 3 | import org.springframework.util.ClassUtils; 4 | import org.springframework.web.multipart.MultipartFile; 5 | import paster.bean.History; 6 | import paster.log.Logger; 7 | import paster.prop.Prop; 8 | 9 | import java.io.*; 10 | import java.net.HttpURLConnection; 11 | import java.net.MalformedURLException; 12 | import java.net.ProtocolException; 13 | import java.net.URL; 14 | import java.util.Date; 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | import java.util.UUID; 18 | 19 | /** 20 | * 工具类 21 | * 针对于文件 22 | */ 23 | public class FileUtils { 24 | 25 | 26 | static String path = ClassUtils.getDefaultClassLoader().getResource("").getPath() + "static/uploadImages/"; 27 | 28 | static Date date; 29 | public static File root = new File("/"); 30 | static File uploadDir = new File(path); 31 | 32 | static { 33 | checkDir(uploadDir); 34 | } 35 | 36 | /** 37 | * 保存上传的文件到本地 38 | * @param multipartFile 被上传的文件 39 | */ 40 | public static Map saveFile(MultipartFile multipartFile, String address) { 41 | Map map = new HashMap(); 42 | String time = datePartition(); 43 | 44 | String filename = multipartFile.getOriginalFilename(); 45 | try { 46 | // 后缀名 47 | String suffixName = LittleTools.getSuffix(filename); 48 | if (suffixName != null) { 49 | // 是否是图片文件 50 | if (LittleTools.isPic(LittleTools.getSuffix(filename))) { 51 | String name = UUID.randomUUID() + suffixName; 52 | multipartFile.transferTo(new File( time + "/" + name)); 53 | Logger.log(Logger.INFO,"[Upload] save the " +filename); 54 | 55 | // 先判断history文件是否存在 56 | History history = HistoryTools.getHistory(address); 57 | if (history == null) { 58 | history = new History(address); 59 | } 60 | HistoryTools.addRecord(history, filename + ":/" + getDir() + "/" + name); 61 | int imageUploadCount = Integer.parseInt(Prop.getProperty("imageUploadCount")); 62 | Prop.modify("imageUploadCount", imageUploadCount+1); 63 | map.put("state", "ok"); 64 | map.put("msg", "/uploadImages/" + getDir() + "/" + name); 65 | } else { 66 | Logger.log(Logger.INFO,"[Upload] 用户上传非图片文件夹"); 67 | map.put("state", "!pic"); 68 | map.put("msg", "不是图片文件"); 69 | } 70 | } 71 | } catch (IOException e) { 72 | e.printStackTrace(); 73 | map.put("state", "error"); 74 | map.put("msg", "出错,请重试"); 75 | } 76 | 77 | return map; 78 | } 79 | 80 | 81 | /** 82 | * 根据时间创建文件夹 83 | * @return 返回文件夹的路径 84 | */ 85 | public static String datePartition() { 86 | date = new Date(); 87 | 88 | int today = date.getDate(); 89 | int toMonth = date.getMonth() + 1; 90 | int toYear = date.getYear() + 1900; 91 | 92 | // D:/uploadImages/2020/2-18 格式 93 | File todayDir = new File(uploadDir.getAbsolutePath() + "/" + toYear + "/" + toMonth + "-" + today); 94 | 95 | checkDir(todayDir); 96 | 97 | return todayDir.getAbsolutePath(); 98 | } 99 | 100 | /** 101 | * 判断uploadImage文件夹是否被创建 102 | */ 103 | public static void checkDir(File dir) { 104 | if (!dir.exists()) dir.mkdirs(); 105 | } 106 | 107 | 108 | /** 109 | * 网络流下载文件 110 | * @param address 网址 111 | */ 112 | public static Map cloneFile(String address, String ip) { 113 | Map map = new HashMap(); 114 | // 获取文件路径 115 | String path = datePartition(); 116 | String suffix = LittleTools.getSuffix(address); 117 | if (suffix == null || !LittleTools.isPic(suffix)) { 118 | Logger.log(Logger.INFO,"[Clone] 用户上传其他文件"); 119 | map.put("state", "!pic"); 120 | map.put("msg", "请上传图片文件!"); 121 | return map; 122 | } 123 | String name = address.split("/")[address.split("/").length-1]; 124 | String filename = UUID.randomUUID() + suffix; 125 | 126 | 127 | try { 128 | // 创建URL网络流对象 129 | URL url = new URL(address); 130 | // 打开链接 131 | HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 132 | // 设置请求方式 133 | conn.setRequestMethod("GET"); 134 | // 设置超时时间 135 | conn.setConnectTimeout(5 * 1000); 136 | // 通过输入流获取图片数据 137 | InputStream is = conn.getInputStream(); 138 | //得到图片的二进制数据,以二进制封装得到数据 139 | byte[] data = readInputStream(is); 140 | File imageFile = new File(path + "/" + filename); 141 | //创建输出流 142 | FileOutputStream outStream = new FileOutputStream(imageFile); 143 | //写入数据 144 | outStream.write(data); 145 | //关闭输出流 146 | outStream.close(); 147 | 148 | History history = HistoryTools.getHistory(ip); 149 | if (history == null) { 150 | history = new History(ip); 151 | } 152 | HistoryTools.addRecord(history, name + ":/" + getDir() + "/" + filename); 153 | Logger.log(Logger.INFO,"[Clone] Clone Successfully"); 154 | 155 | map.put("state", "ok"); 156 | map.put("org", name); 157 | map.put("msg", "/uploadImages/" + getDir() + "/" + filename); 158 | return map; 159 | } catch (MalformedURLException e) { 160 | Logger.log(Logger.WARN,"[Clone] 没有指定协议"); 161 | map.put("state", "!full"); 162 | map.put("msg", "地址错误,请重新输入网址!"); 163 | return map; 164 | } catch (FileNotFoundException e) { 165 | Logger.log(Logger.WARN,"[Clone] 保存错误"); 166 | map.put("state", "repeat"); 167 | map.put("msg", "克隆失败,请重试!"); 168 | return map; 169 | } catch (ProtocolException e) { 170 | Logger.log(Logger.WARN,"[Clone] 无法打开传输"); 171 | map.put("state", "!url"); 172 | map.put("msg", "无法克隆此图片,请检查网址无误后再进行上传!"); 173 | return map; 174 | } catch (IOException e) { 175 | map.put("state", "error"); 176 | map.put("msg", "上传错误,请重新上传!"); 177 | Logger.log(Logger.WARN,"[Clone] 上传错误"); 178 | return map; 179 | } 180 | } 181 | 182 | /** 183 | * 获取网络图片的字节数组 184 | * @param is 网络流得到的输入流 185 | * @return 返回字节数组 186 | * @throws Exception 187 | */ 188 | public static byte[] readInputStream(InputStream is) { 189 | ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 190 | // 创建缓冲 191 | byte[] buffer = new byte[1024]; 192 | int len = 0; 193 | while (true) { 194 | try { 195 | if (!((len = is.read(buffer)) != -1)) break; 196 | } catch (IOException e) { 197 | e.printStackTrace(); 198 | } 199 | outputStream.write(buffer, 0, len); 200 | } 201 | // 关闭输入流 202 | try { 203 | is.close(); 204 | } catch (IOException e) { 205 | e.printStackTrace(); 206 | } 207 | // 输出字节数组 208 | return outputStream.toByteArray(); 209 | } 210 | 211 | public static String getDir() { 212 | date = new Date(); 213 | 214 | int today = date.getDate(); 215 | int toMonth = date.getMonth() + 1; 216 | int toYear = date.getYear() + 1900; 217 | 218 | return toYear + "/" + toMonth + "-" + today; 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /src/main/java/paster/utlis/HistoryTools.java: -------------------------------------------------------------------------------- 1 | package paster.utlis; 2 | 3 | import paster.bean.History; 4 | 5 | import java.io.*; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.Properties; 9 | 10 | public class HistoryTools { 11 | 12 | static FileOutputStream fileOutputStream; 13 | static Properties properties; 14 | 15 | public static void createHistoryFile(History history) { 16 | String name = history.getUrl(); 17 | try { 18 | fileOutputStream = new FileOutputStream("history/" + name + ".txt", true); 19 | } catch (FileNotFoundException e) { 20 | e.printStackTrace(); 21 | } 22 | } 23 | 24 | 25 | public static int addRecord(History history, String value) { 26 | 27 | 28 | try { 29 | int count = history.getCount(); 30 | write(history.getFileOutputStream(), count + "=" + value + "\n"); 31 | history.setCount(count + 1); 32 | return 0; 33 | } catch (IOException e) { 34 | e.printStackTrace(); 35 | return -1; 36 | } 37 | } 38 | 39 | public static String getRecord(History history, int count) { 40 | properties = history.getProperties(); 41 | String str = null; 42 | try { 43 | properties.load(history.getFileInputStream()); 44 | str = properties.getProperty(String.valueOf(count)); 45 | } catch (IOException e) { 46 | e.printStackTrace(); 47 | } 48 | return str; 49 | } 50 | 51 | 52 | public static void write(FileOutputStream fileOutputStream, String value) throws IOException { 53 | fileOutputStream.write(value.getBytes()); 54 | } 55 | 56 | 57 | /** 58 | * 从文件获取History对象 59 | */ 60 | public static History getHistory(String name) { 61 | if (!new File("history/" + name + ".txt").exists()) { 62 | return null; 63 | } 64 | String lastLine = null; 65 | try { 66 | lastLine = readLastLine(name); 67 | } catch (IOException e) { 68 | e.printStackTrace(); 69 | } 70 | History history = new History(name); 71 | int count = Integer.parseInt(lastLine.split("=")[0]) + 1; 72 | history.setCount(count); 73 | try { 74 | history.setFileInputStream(new FileInputStream("history/" + name + ".txt")); 75 | } catch (FileNotFoundException e) { 76 | e.printStackTrace(); 77 | } 78 | return history; 79 | } 80 | 81 | 82 | public static String readLastLine(String name) throws IOException { 83 | File file = new File("history/" + name + ".txt"); 84 | 85 | BufferedReader bf = new BufferedReader(new FileReader(file)); 86 | 87 | String buf = null; 88 | String str = null; 89 | 90 | // 1024byte *1024byte = 1MB 91 | if (file.length() > 1024 * 1024) { 92 | // 当文件超过1M大小的时候,跳过文本长度的2/3 93 | bf.skip(file.length() / 3 * 2); 94 | } 95 | 96 | while ((buf = bf.readLine()) != null) { 97 | str = buf; 98 | } 99 | return str; 100 | } 101 | 102 | public static List allImg(History history) { 103 | List list = new ArrayList<>(); 104 | for (int i = 0; i < history.getCount(); i++) { 105 | list.add(HistoryTools.getRecord(history, i).split(":")[1]); 106 | } 107 | 108 | return list; 109 | } 110 | 111 | /** 112 | * history文件夹是否存在 113 | * @return 114 | */ 115 | public static boolean historyExist() { 116 | return new File("history/").exists(); 117 | } 118 | } -------------------------------------------------------------------------------- /src/main/java/paster/utlis/IPUtils.java: -------------------------------------------------------------------------------- 1 | package paster.utlis; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | 5 | public class IPUtils { 6 | 7 | 8 | /** 9 | * 获取请求IP地址 10 | * @param request 请求 11 | * @return 返回IP地址 12 | */ 13 | public static String getIpAddress(HttpServletRequest request) { 14 | String ip = request.getHeader("x-forwarded-for"); 15 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 16 | ip = request.getHeader("Proxy-Client-IP"); 17 | } 18 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 19 | ip = request.getHeader("WL-Proxy-Client-IP"); 20 | } 21 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 22 | ip = request.getHeader("HTTP_CLIENT_IP"); 23 | } 24 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 25 | ip = request.getHeader("HTTP_X_FORWARDED_FOR"); 26 | } 27 | if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 28 | ip = request.getRemoteAddr(); 29 | } 30 | ip = ip.replace(":", "."); 31 | return ip; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/paster/utlis/LittleTools.java: -------------------------------------------------------------------------------- 1 | package paster.utlis; 2 | 3 | import java.text.DecimalFormat; 4 | 5 | public class LittleTools { 6 | 7 | /** 8 | * 获取文件名的后缀名 9 | * @param filename 文件名 10 | * @return 后缀名 11 | */ 12 | public static String getSuffix(String filename) { 13 | int i; 14 | if ((i = filename.lastIndexOf(".")) != -1) { 15 | String suffix = filename.substring(i); 16 | 17 | return suffix; 18 | } 19 | return null; 20 | } 21 | 22 | /** 23 | * 判断后缀名是否是图片文件 24 | * @param suffixName 后缀名 25 | * @return 是否 26 | */ 27 | public static boolean isPic(String suffixName) { 28 | if (suffixName.equals(".jpeg") || suffixName.equals(".jpg") || suffixName.equals(".png") || suffixName.equals(".gif") || suffixName.equals(".svg") || suffixName.equals(".bmp") || suffixName.equals(".ico") || suffixName.equals(".tiff")) { 29 | return true; 30 | } else { 31 | System.out.println("用户上传了非图片文件"); 32 | return false; 33 | } 34 | } 35 | 36 | /** 37 | * 获取项目所在根目录的剩余容量 38 | * @return 项目所在的根目录剩余容量 39 | */ 40 | public static String freeSize() { 41 | return new DecimalFormat("#.00").format(((float) FileUtils.root.getFreeSpace() / 1073741824)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # multipart ???? 2 | # spring???????? 3 | spring.servlet.multipart.max-file-size=30MB 4 | # spring?????? 5 | spring.servlet.multipart.max-request-size=30MB 6 | 7 | # spring boot ???? 8 | spring.devtools.restart.enabled=true 9 | 10 | spring.mvc.static-path-pattern=/** 11 | spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/ 12 | 13 | # thymeleaf?? 14 | # thymeleaf ?? 15 | spring.thymeleaf.cache=false 16 | # thymeleaf ???? 17 | spring.thymeleaf.encoding=UTF-8 18 | # thymeleaf MIME 19 | spring.thymeleaf.servlet.content-type=text/html 20 | # thymeleaf ?? 21 | spring.thymeleaf.mode=HTML5 22 | 23 | spring.thymeleaf.prefix=classpath:/templates/ 24 | # thymeleaf ???? 25 | spring.mvc.view.suffix=.html -------------------------------------------------------------------------------- /src/main/resources/static/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Programming-With-Love/PingeBed/f0f705cee5fe85fd8bf8fa578f01f5fdf59b9c0d/src/main/resources/static/add.png -------------------------------------------------------------------------------- /src/main/resources/static/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Programming-With-Love/PingeBed/f0f705cee5fe85fd8bf8fa578f01f5fdf59b9c0d/src/main/resources/static/close.png -------------------------------------------------------------------------------- /src/main/resources/static/css/admin/admin.css: -------------------------------------------------------------------------------- 1 | .cover-container { 2 | width: 800px; 3 | position: relative; 4 | margin-left: auto; 5 | margin-right: auto; 6 | height: 100%; 7 | } 8 | .login-wrapper { 9 | position: absolute; 10 | left: 225px; 11 | transition: all 1s ease-in-out; 12 | width: 350px; 13 | height: 100%; 14 | background-color: white; 15 | border-radius: 10px; 16 | } 17 | .login { 18 | width: 250px; 19 | position: absolute; 20 | left: 50px; 21 | height: 100%; 22 | } 23 | .login > div { 24 | height: 25%; 25 | width: 100%; 26 | } 27 | .login-wrapper-animate { 28 | transform: rotateY(90deg); 29 | opacity: 0; 30 | } 31 | .admin-wrapper { 32 | position: absolute; 33 | left: 225px; 34 | transition: all 1s ease-in-out; 35 | width: 350px; 36 | height: 100%; 37 | background-color: white; 38 | border-radius: 10px; 39 | 40 | transform: rotateY(-90deg); 41 | } 42 | .admin-wrapper-animate { 43 | transform: rotateY(0deg); 44 | } 45 | .admin { 46 | width: 250px; 47 | position: absolute; 48 | left: 50px; 49 | height: 100%; 50 | } 51 | .admin > div { 52 | width: 100%; 53 | float: left; 54 | height: 16%; 55 | } 56 | div > p { 57 | float: left; 58 | font-size: 18px; 59 | line-height: 18px; 60 | } -------------------------------------------------------------------------------- /src/main/resources/static/css/bs4.pop.css: -------------------------------------------------------------------------------- 1 | .modal[data-drag="draged"] .modal-dialog{ 2 | margin: 0; 3 | position: absolute; 4 | } 5 | 6 | 7 | .alert-container{ 8 | position: fixed; 9 | } 10 | .alert-container .alert{ 11 | box-shadow: 0 5px 5px rgba(0,0,0,0.1); 12 | } 13 | 14 | #alert-container-topleft{ 15 | top: 10px; 16 | left: 10px; 17 | } 18 | 19 | #alert-container-topcenter{ 20 | top: 10px; 21 | left: 50%; 22 | transform: translate(-50%, 0); 23 | } 24 | 25 | #alert-container-topright{ 26 | top: 10px; 27 | right: 10px; 28 | } 29 | 30 | #alert-container-bottomleft{ 31 | bottom: 10px; 32 | left: 10px; 33 | } 34 | 35 | #alert-container-bottomcenter{ 36 | bottom: 10px; 37 | left: 50%; 38 | transform: translate(-50%, 0); 39 | } 40 | 41 | #alert-container-bottomright{ 42 | bottom: 10px; 43 | right: 10px; 44 | } 45 | 46 | #alert-container-center{ 47 | top: 50%; 48 | left: 50%; 49 | transform: translate(-50%, -50%); 50 | } 51 | 52 | -------------------------------------------------------------------------------- /src/main/resources/static/css/history/style.css: -------------------------------------------------------------------------------- 1 | article, 2 | aside, 3 | details, 4 | figcaption, 5 | figure, 6 | footer, 7 | header, 8 | hgroup, 9 | main, 10 | nav, 11 | section, 12 | summary { 13 | display: block 14 | } 15 | 16 | audio, 17 | canvas, 18 | video { 19 | display: inline-block 20 | } 21 | 22 | audio:not([controls]) { 23 | display: none; 24 | height: 0 25 | } 26 | 27 | [hidden] { 28 | display: none 29 | } 30 | 31 | html { 32 | font-family: sans-serif; 33 | -ms-text-size-adjust: 100%; 34 | -webkit-text-size-adjust: 100% 35 | } 36 | 37 | body { 38 | margin: 0 39 | } 40 | 41 | a:focus { 42 | outline: thin dotted 43 | } 44 | 45 | a:active, 46 | a:hover { 47 | outline: 0 48 | } 49 | 50 | h1 { 51 | font-size: 2em; 52 | margin: .67em 0 53 | } 54 | 55 | abbr[title] { 56 | border-bottom: 1px dotted 57 | } 58 | 59 | b, 60 | strong { 61 | font-weight: 700 62 | } 63 | 64 | dfn { 65 | font-style: italic 66 | } 67 | 68 | hr { 69 | -moz-box-sizing: content-box; 70 | box-sizing: content-box; 71 | height: 0 72 | } 73 | 74 | mark { 75 | background: #ff0; 76 | color: #000 77 | } 78 | 79 | code, 80 | kbd, 81 | pre, 82 | samp { 83 | font-family: monospace, serif; 84 | font-size: 1em 85 | } 86 | 87 | pre { 88 | white-space: pre-wrap 89 | } 90 | 91 | q { 92 | quotes: "\201C" "\201D" "\2018" "\2019" 93 | } 94 | 95 | small { 96 | font-size: 80% 97 | } 98 | 99 | sub, 100 | sup { 101 | font-size: 75%; 102 | line-height: 0; 103 | position: relative; 104 | vertical-align: baseline 105 | } 106 | 107 | sup { 108 | top: -.5em 109 | } 110 | 111 | sub { 112 | bottom: -.25em 113 | } 114 | 115 | img { 116 | border: 0 117 | } 118 | 119 | svg:not(:root) { 120 | overflow: hidden 121 | } 122 | 123 | figure { 124 | margin: 0 125 | } 126 | 127 | fieldset { 128 | border: 1px solid silver; 129 | margin: 0 2px; 130 | padding: .35em .625em .75em 131 | } 132 | 133 | legend { 134 | border: 0; 135 | padding: 0 136 | } 137 | 138 | button, 139 | input, 140 | select, 141 | textarea { 142 | font-family: inherit; 143 | font-size: 100%; 144 | margin: 0 145 | } 146 | 147 | button, 148 | input { 149 | line-height: normal 150 | } 151 | 152 | button, 153 | select { 154 | text-transform: none 155 | } 156 | 157 | button, 158 | html input[type=button], 159 | input[type=reset], 160 | input[type=submit] { 161 | -webkit-appearance: button; 162 | cursor: pointer 163 | } 164 | 165 | button[disabled], 166 | html input[disabled] { 167 | cursor: default 168 | } 169 | 170 | input[type=checkbox], 171 | input[type=radio] { 172 | box-sizing: border-box; 173 | padding: 0 174 | } 175 | 176 | input[type=search] { 177 | -webkit-appearance: textfield; 178 | -moz-box-sizing: content-box; 179 | -webkit-box-sizing: content-box; 180 | box-sizing: content-box 181 | } 182 | 183 | input[type=search]::-webkit-search-cancel-button, 184 | input[type=search]::-webkit-search-decoration { 185 | -webkit-appearance: none 186 | } 187 | 188 | button::-moz-focus-inner, 189 | input::-moz-focus-inner { 190 | border: 0; 191 | padding: 0 192 | } 193 | 194 | textarea { 195 | overflow: auto; 196 | vertical-align: top 197 | } 198 | 199 | table { 200 | border-collapse: collapse; 201 | border-spacing: 0 202 | } 203 | *, 204 | *:after, 205 | *:before { 206 | -webkit-box-sizing: border-box; 207 | -moz-box-sizing: border-box; 208 | box-sizing: border-box 209 | } 210 | 211 | .clearfix:before, 212 | .clearfix:after { 213 | content: ''; 214 | display: table 215 | } 216 | 217 | .clearfix:after { 218 | clear: both 219 | } 220 | 221 | body { 222 | background: #d3eee2; 223 | color: #2e3444; 224 | font-size: 100%; 225 | line-height: 1.25; 226 | font-family: lato, sans-serif; 227 | font-weight: 300 228 | } 229 | 230 | a { 231 | color: #ff2a48; 232 | text-decoration: none; 233 | outline: 0 234 | } 235 | 236 | a:hover, 237 | a:focus { 238 | color: #2e3444 239 | } 240 | 241 | section { 242 | padding: 1em; 243 | text-align: center 244 | } 245 | 246 | body { 247 | width: 100%; 248 | background: #494A5F; 249 | background-size: 100% 100%; 250 | min-width: max-content; 251 | background-position: center; 252 | background-repeat: no-repeat; 253 | background-attachment: fixed; 254 | } 255 | 256 | /* .t_show{ 257 | width: 100%; 258 | height: 100%; 259 | position: fixed; 260 | background: rgba(0,0,0,0.6); 261 | top: 0; 262 | z-index: 100; 263 | cursor: pointer; 264 | } 265 | .t_img,.t_images{ 266 | width: 1200px; 267 | height: 760px; 268 | position: absolute; 269 | top: 0; 270 | right: 0; 271 | left: 0; 272 | bottom: 0; 273 | margin: auto; 274 | z-index: 200; 275 | } 276 | .t_images{ 277 | z-index: 300; 278 | } */ 279 | #grid li:hover a img{ 280 | transition: all ease 1s; 281 | transform:scale(1.4); 282 | } 283 | 284 | .grid-wrap { 285 | clear: both; 286 | margin: 0 auto; 287 | padding: 0; 288 | max-width: 1260px 289 | } 290 | 291 | .grid { 292 | margin: 30px auto; 293 | padding: 0; 294 | list-style: none; 295 | min-height: 500px 296 | } 297 | 298 | .grid li { 299 | display: inline-block; 300 | overflow: hidden; 301 | width: 314px; 302 | text-align: left; 303 | vertical-align: top 304 | } 305 | 306 | .js .grid li { 307 | display: none; 308 | float: left 309 | } 310 | 311 | .js .grid.loaded li { 312 | display: block 313 | } 314 | 315 | .title-box h2 { 316 | display: block; 317 | margin: 7px; 318 | padding: 20px; 319 | background: #2e3444; 320 | color: #d3eee2; 321 | text-transform: uppercase; 322 | letter-spacing: 1px; 323 | font-weight: 300 324 | } 325 | 326 | .title-box h2 a { 327 | display: block; 328 | font-weight: 900 329 | } 330 | 331 | .title-box h2 a:hover { 332 | color: #d3eee2 333 | } 334 | 335 | .grid li>a, 336 | .grid li img { 337 | border-radius: 2px; 338 | display: block; 339 | outline: 0; 340 | border: 0 341 | } 342 | 343 | .grid li>a { 344 | position: relative; 345 | overflow: hidden; 346 | margin: 7px 347 | } 348 | 349 | .grid .curtain { 350 | position: absolute; 351 | top: 0; 352 | left: 0; 353 | z-index: 100; 354 | width: 100%; 355 | height: 100%; 356 | background: #333 357 | } 358 | 359 | .grid.swipe-right .curtain { 360 | -webkit-transform: translate3d(-100%, 0, 0); 361 | transform: translate3d(-100%, 0, 0) 362 | } 363 | 364 | .grid.swipe-down .curtain { 365 | -webkit-transform: translate3d(0, -100%, 0); 366 | transform: translate3d(0, -100%, 0) 367 | } 368 | 369 | .grid.swipe-rotate .curtain { 370 | width: 200%; 371 | height: 200%; 372 | -webkit-transform: rotate3d(0, 0, 1, 90deg); 373 | transform: rotate3d(0, 0, 1, 90deg); 374 | -webkit-transform-origin: top left; 375 | transform-origin: top left 376 | } 377 | 378 | .grid .curtain::after { 379 | position: absolute; 380 | top: 0; 381 | left: 0; 382 | width: 100%; 383 | height: 100%; 384 | background: #000; 385 | content: '' 386 | } 387 | 388 | .grid.swipe-right .curtain::after, 389 | .grid.swipe-rotate .curtain::after { 390 | left: -100% 391 | } 392 | 393 | .grid.swipe-down .curtain::after { 394 | top: -100% 395 | } 396 | 397 | .grid li h3 { 398 | position: absolute; 399 | bottom: 0; 400 | left: 0; 401 | margin: 0; 402 | padding: 20px; 403 | width: 100%; 404 | background: #2e3444; 405 | color: #d3eee2; 406 | text-align: right; 407 | text-transform: uppercase; 408 | letter-spacing: 1px; 409 | font-weight: 800; 410 | font-size: 1em; 411 | -webkit-transition: -webkit-transform .2s, color .2s; 412 | transition: transform .2s, color .2s 413 | } 414 | 415 | .grid li>a::before { 416 | position: absolute; 417 | top: 0; 418 | left: 0; 419 | width: 100.5%; 420 | height: 100.5%; 421 | border: 0; 422 | background: transparent; 423 | content: ''; 424 | -webkit-transition: border-width .2s, border-color .2s; 425 | transition: border-width .2s, border-color .2s 426 | } 427 | 428 | .grid li.shown:hover h3 { 429 | color: #fff; 430 | -webkit-transform: translate3d(0, -30px, 0); 431 | transform: translate3d(0, -30px, 0) 432 | } 433 | 434 | .grid li.shown:hover>a::before { 435 | border-width: 14px; 436 | border-color: #2e3444 437 | } 438 | 439 | .grid.swipe-right li.animate .curtain { 440 | -webkit-animation: swipeRight 1.5s cubic-bezier(.6, 0, .4, 1) forwards; 441 | animation: swipeRight 1.5s cubic-bezier(.6, 0, .4, 1) forwards 442 | } 443 | 444 | @-webkit-keyframes swipeRight { 445 | 0% {} 446 | 50%, 447 | 60% { 448 | -webkit-transform: translate3d(0, 0, 0) 449 | } 450 | 100% { 451 | -webkit-transform: translate3d(100%, 0, 0) 452 | } 453 | } 454 | 455 | @keyframes swipeRight { 456 | 0% {} 457 | 50%, 458 | 60% { 459 | -webkit-transform: translate3d(0, 0, 0); 460 | transform: translate(0) 461 | } 462 | 100% { 463 | -webkit-transform: translate3d(100%, 0, 0); 464 | transform: translate3d(100%, 0, 0) 465 | } 466 | } 467 | 468 | .grid.swipe-down li.animate .curtain { 469 | -webkit-animation: swipeDown 1.5s cubic-bezier(.6, 0, .4, 1) forwards; 470 | animation: swipeDown 1.5s cubic-bezier(.6, 0, .4, 1) forwards 471 | } 472 | 473 | @-webkit-keyframes swipeDown { 474 | 0% {} 475 | 50%, 476 | 60% { 477 | -webkit-transform: translate3d(0, 0, 0) 478 | } 479 | 100% { 480 | -webkit-transform: translate3d(0, 100%, 0) 481 | } 482 | } 483 | 484 | @keyframes swipeDown { 485 | 0% {} 486 | 50%, 487 | 60% { 488 | -webkit-transform: translate(0); 489 | transform: translate(0) 490 | } 491 | 100% { 492 | transform: translate3d(0, 100%, 0); 493 | transform: translate3d(0, 100%, 0) 494 | } 495 | } 496 | 497 | .grid.swipe-rotate li.animate .curtain { 498 | -webkit-animation: swipeRotate 1.5s ease forwards; 499 | animation: swipeRotate 1.5s ease forwards 500 | } 501 | 502 | @-webkit-keyframes swipeRotate { 503 | 0% {} 504 | 50%, 505 | 60% { 506 | -webkit-transform: rotate3d(0, 0, 1, 0deg) 507 | } 508 | 100% { 509 | -webkit-transform: rotate3d(0, 0, 1, -90deg) 510 | } 511 | } 512 | 513 | @keyframes swipeRotate { 514 | 0% {} 515 | 50%, 516 | 60% { 517 | -webkit-transform: rotate3d(0, 0, 1, 0deg); 518 | transform: rotate3d(0, 0, 1, 0deg) 519 | } 520 | 100% { 521 | -webkit-transform: rotate3d(0, 0, 1, -90deg); 522 | transform: rotate3d(0, 0, 1, -90deg) 523 | } 524 | } 525 | 526 | .grid li.animate .curtain::after { 527 | -webkit-animation: fadeOut 1.5s ease forwards; 528 | animation: fadeOut 1.5s ease forwards; 529 | -webkit-animation-delay: inherit; 530 | animation-delay: inherit 531 | } 532 | 533 | @-webkit-keyframes fadeOut { 534 | 0% {} 535 | 50%, 536 | 60% { 537 | opacity: 1 538 | } 539 | 100% { 540 | opacity: 0 541 | } 542 | } 543 | 544 | @keyframes fadeOut { 545 | 0% {} 546 | 50%, 547 | 60% { 548 | opacity: 1 549 | } 550 | 100% { 551 | opacity: 0 552 | } 553 | } 554 | 555 | .js .grid li img, 556 | .js .grid li h3 { 557 | visibility: hidden 558 | } 559 | 560 | .grid li.animate img, 561 | .grid li.animate h3 { 562 | -webkit-animation: showMe 1.5s step-end forwards; 563 | animation: showMe 1.5s step-end forwards 564 | } 565 | 566 | @-webkit-keyframes showMe { 567 | from { 568 | visibility: hidden 569 | } 570 | 60%, 571 | 100% { 572 | visibility: visible 573 | } 574 | } 575 | 576 | @keyframes showMe { 577 | from { 578 | visibility: hidden 579 | } 580 | 60%, 581 | 100% { 582 | visibility: visible 583 | } 584 | } 585 | 586 | .grid li.shown img, 587 | .grid li.shown h3 { 588 | visibility: visible 589 | } 590 | 591 | @keyframes showMe { 592 | from { 593 | visibility: hidden 594 | } 595 | 60%, 596 | 100% { 597 | visibility: visible 598 | } 599 | } 600 | 601 | .grid li.shown img, 602 | .grid li.shown h3 { 603 | visibility: visible 604 | } -------------------------------------------------------------------------------- /src/main/resources/static/css/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | text-align: center; 3 | background-color: #494A5F; 4 | } 5 | 6 | .site { 7 | width: 100%; 8 | height: 100%; 9 | margin-top: 15px; 10 | } 11 | .site-inner { 12 | height: 600px; 13 | vertical-align: middle; 14 | padding: 60px 0px; 15 | } 16 | .cover-container { 17 | text-align: center; 18 | display: table; 19 | width: 60%; 20 | margin-right: auto; 21 | margin-left: auto; 22 | height: 100%; 23 | } 24 | .cover-inner { 25 | color: white; 26 | height: 100%; 27 | width: 100%; 28 | display: table-cell; 29 | vertical-align: middle; 30 | } 31 | .dialog-select { 32 | background-color: white; 33 | position: absolute; 34 | width: 600px; 35 | height: 450px; 36 | border-radius: 25px; 37 | display: none; 38 | } 39 | .dialog-header { 40 | background-color: rgb(231, 231, 231); 41 | color: white; 42 | padding-top: 20px; 43 | padding-left: 20px; 44 | border-radius: 25px 25px 0px 0px; 45 | } 46 | .dialog-header > p { 47 | color: black; 48 | font-size: 25px; 49 | text-align: left; 50 | margin: 0px; 51 | } 52 | .dialog-close { 53 | height: 30px; 54 | float: right; 55 | margin-right: 20px; 56 | } 57 | .upload-method { 58 | padding: 20px 30px 0px 30px; 59 | background-color: rgb(231, 231, 231); 60 | } 61 | .upload-method > a { 62 | color: black; 63 | cursor: default; 64 | text-decoration: none; 65 | display: inline-block; 66 | width: 40%; 67 | text-align: center; 68 | font-size: 1.5em; 69 | transition-property: background; 70 | transition-duration: 1s; 71 | -moz-transition-property: background; /* Firefox 4 */ 72 | -moz-transition-duration: 1s; /* Firefox 4 */ 73 | -webkit-transition-property: background; /* Safari and Chrome */ 74 | -webkit-transition-duration: 1s; /* Safari and Chrome */ 75 | -o-transition-property: background; /* Opera */ 76 | -o-transition-duration: 1s; /* Opera */ 77 | } 78 | .upload-method > a:hover:not(.selected) { 79 | color: black; 80 | background: antiquewhite; 81 | } 82 | .dialog-body > button { 83 | float: right; 84 | margin-top: 10px; 85 | margin-right: 25px; 86 | width: 100px; 87 | } 88 | .upload-file > a > img { 89 | width: 370px; 90 | height: 260px; 91 | margin-top: 10px; 92 | } 93 | .header-upload { 94 | margin-right: 3%; 95 | -moz-transition:width 2s; /* Firefox 4 */ 96 | -webkit-transition:width 2s; /* Safari and Chrome */ 97 | -o-transition:width 2s; /* Opera */ 98 | } 99 | .header-clone { 100 | margin-left: 3%; 101 | } 102 | .navbar-brand > img { 103 | display: inline; 104 | } 105 | .upload-area { 106 | background-color: white; 107 | padding: 0px 30px; 108 | } 109 | .selected { 110 | background-color: white; 111 | } 112 | .cp:hover { 113 | cursor: pointer; 114 | } -------------------------------------------------------------------------------- /src/main/resources/static/css/mobile.css: -------------------------------------------------------------------------------- 1 | .navbar-toggler { 2 | display: none; 3 | } 4 | @media (max-width: 992px) { 5 | .navbar-toggler { 6 | display: block; 7 | } 8 | } 9 | 10 | @media (max-width: 768px) { 11 | .navbar { 12 | z-index: 8848; 13 | } 14 | .upload-file > a > img { 15 | width: 100%; 16 | } 17 | .dialog-select { 18 | width: 90%; 19 | } 20 | .upload-area { 21 | padding: 0; 22 | margin-right: auto; 23 | margin-left: auto; 24 | width: 95%; 25 | } 26 | .navbar-toggler { 27 | display: block; 28 | } 29 | 30 | .site { 31 | margin-top: 0px; 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/resources/static/css/show.css: -------------------------------------------------------------------------------- 1 | .instance { 2 | margin-top: 20px; 3 | } 4 | .preview { 5 | height: auto; 6 | width: auto; 7 | max-height: 192px; 8 | max-width: 192px; 9 | } 10 | .instance-address{ 11 | margin-top: 10px; 12 | } -------------------------------------------------------------------------------- /src/main/resources/static/doge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Programming-With-Love/PingeBed/f0f705cee5fe85fd8bf8fa578f01f5fdf59b9c0d/src/main/resources/static/doge.png -------------------------------------------------------------------------------- /src/main/resources/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Programming-With-Love/PingeBed/f0f705cee5fe85fd8bf8fa578f01f5fdf59b9c0d/src/main/resources/static/favicon.ico -------------------------------------------------------------------------------- /src/main/resources/static/js/admin/admin.js: -------------------------------------------------------------------------------- 1 | function login() { 2 | var password = $("#login-password").val(); 3 | axios.get('/api/login', { 4 | params: { 5 | "password": password 6 | } 7 | }) 8 | .then(function (response) { 9 | if (response.data.msg == "success") { 10 | console.log("登录成功"); 11 | 12 | var conf = response.data.data; 13 | if (conf[0] == "true") { 14 | $(".switch").toggleClass("switch-on"); 15 | $("#turn").attr("checked", true); 16 | } 17 | $("#imageUploadCount").val(conf[1]); 18 | $("#size").val(conf[2]); 19 | $("#password").val(conf[3]); 20 | $("#version").val(conf[4]); 21 | overturn(); 22 | 23 | } else { 24 | $("#login-password").val(""); 25 | $("#login-password").css("border", "red solid 1px"); 26 | } 27 | console.log(response); 28 | }) 29 | .catch(function (error) { 30 | console.log(error); 31 | }); 32 | } 33 | 34 | function changeConf() { 35 | var list = ["anonymous", "imageUploadCount", "size", "password", "version"]; 36 | $.each(list, function (i, value) { 37 | if (i == 0) { 38 | var param = {"key" : value, "value": $("#turn").is(":checked")}; 39 | } else { 40 | var param = {"key" : value, "value" : $("#" + value).val()} 41 | } 42 | axios.get('/api/setConf', { 43 | params: param 44 | }) 45 | .then(function (response) { 46 | if (response.data.msg == "success") { 47 | } else { 48 | bs4pop.notice("配置错误,请重试", {position: "bottomright", type: "secondary"}); 49 | } 50 | }) 51 | .catch(function (response) { 52 | console.log(response); 53 | }) 54 | }); 55 | bs4pop.notice("配置已更新,请刷新此页面", {position: "bottomright", type: "secondary"}); 56 | } 57 | 58 | 59 | function reload() { 60 | axios.get('/api/reload') 61 | .then(function (response) { 62 | if (response.data.msg == "success") { 63 | bs4pop.notice("config.ini文件重载成功!请刷新页面", {position: "bottomright", type: "secondary"}); 64 | overturnback(); 65 | } else { 66 | bs4pop.notice("重载出错,请检查config.ini文件", {position: "bottomright", type: "secondary"}); 67 | } 68 | }) 69 | } 70 | 71 | function logout() { 72 | axios.get('/api/logout') 73 | .then(function (response) { 74 | if (response.data.msg == "success") { 75 | bs4pop.notice("即将注销", {position: "bottomright", type: "secondary"}); 76 | overturnback(); 77 | } 78 | }) 79 | } 80 | 81 | 82 | function overturn() { 83 | $(".login-wrapper").css("transform", "rotateY(90deg)"); 84 | $(".login-wrapper").css("opacity", "0"); 85 | setTimeout(function () { 86 | $(".admin-wrapper").css("transform", "rotateY(0deg)"); 87 | $(".admin-wrapper").css("opacity", "1"); 88 | }, 1000); 89 | $("#login-password").val(""); 90 | } 91 | 92 | function overturnback() { 93 | $(".admin-wrapper").css("transform", "rotateY(90deg)"); 94 | $(".admin-wrapper").css("opacity", "0"); 95 | setTimeout(function () { 96 | $(".login-wrapper").css("transform", "rotateY(0deg)"); 97 | $(".login-wrapper").css("opacity", "1"); 98 | }, 1000); 99 | } -------------------------------------------------------------------------------- /src/main/resources/static/js/axios.min.js: -------------------------------------------------------------------------------- 1 | /* axios v0.19.2 | (c) 2020 by Matt Zabriskie */ 2 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function r(e){var t=new s(e),n=i(s.prototype.request,t);return o.extend(n,s.prototype,t),o.extend(n,t),n}var o=n(2),i=n(3),s=n(4),a=n(22),u=n(10),c=r(u);c.Axios=s,c.create=function(e){return r(a(c.defaults,e))},c.Cancel=n(23),c.CancelToken=n(24),c.isCancel=n(9),c.all=function(e){return Promise.all(e)},c.spread=n(25),e.exports=c,e.exports.default=c},function(e,t,n){"use strict";function r(e){return"[object Array]"===j.call(e)}function o(e){return"undefined"==typeof e}function i(e){return null!==e&&!o(e)&&null!==e.constructor&&!o(e.constructor)&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}function s(e){return"[object ArrayBuffer]"===j.call(e)}function a(e){return"undefined"!=typeof FormData&&e instanceof FormData}function u(e){var t;return t="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function c(e){return"string"==typeof e}function f(e){return"number"==typeof e}function p(e){return null!==e&&"object"==typeof e}function d(e){return"[object Date]"===j.call(e)}function l(e){return"[object File]"===j.call(e)}function h(e){return"[object Blob]"===j.call(e)}function m(e){return"[object Function]"===j.call(e)}function y(e){return p(e)&&m(e.pipe)}function g(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function v(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function x(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product&&"NativeScript"!==navigator.product&&"NS"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)}function w(e,t){if(null!==e&&"undefined"!=typeof e)if("object"!=typeof e&&(e=[e]),r(e))for(var n=0,o=e.length;n=200&&e<300}};u.headers={common:{Accept:"application/json, text/plain, */*"}},i.forEach(["delete","get","head"],function(e){u.headers[e]={}}),i.forEach(["post","put","patch"],function(e){u.headers[e]=i.merge(a)}),e.exports=u},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){r.forEach(e,function(n,r){r!==t&&r.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[r])})}},function(e,t,n){"use strict";var r=n(2),o=n(13),i=n(5),s=n(16),a=n(19),u=n(20),c=n(14);e.exports=function(e){return new Promise(function(t,f){var p=e.data,d=e.headers;r.isFormData(p)&&delete d["Content-Type"];var l=new XMLHttpRequest;if(e.auth){var h=e.auth.username||"",m=e.auth.password||"";d.Authorization="Basic "+btoa(h+":"+m)}var y=s(e.baseURL,e.url);if(l.open(e.method.toUpperCase(),i(y,e.params,e.paramsSerializer),!0),l.timeout=e.timeout,l.onreadystatechange=function(){if(l&&4===l.readyState&&(0!==l.status||l.responseURL&&0===l.responseURL.indexOf("file:"))){var n="getAllResponseHeaders"in l?a(l.getAllResponseHeaders()):null,r=e.responseType&&"text"!==e.responseType?l.response:l.responseText,i={data:r,status:l.status,statusText:l.statusText,headers:n,config:e,request:l};o(t,f,i),l=null}},l.onabort=function(){l&&(f(c("Request aborted",e,"ECONNABORTED",l)),l=null)},l.onerror=function(){f(c("Network Error",e,null,l)),l=null},l.ontimeout=function(){var t="timeout of "+e.timeout+"ms exceeded";e.timeoutErrorMessage&&(t=e.timeoutErrorMessage),f(c(t,e,"ECONNABORTED",l)),l=null},r.isStandardBrowserEnv()){var g=n(21),v=(e.withCredentials||u(y))&&e.xsrfCookieName?g.read(e.xsrfCookieName):void 0;v&&(d[e.xsrfHeaderName]=v)}if("setRequestHeader"in l&&r.forEach(d,function(e,t){"undefined"==typeof p&&"content-type"===t.toLowerCase()?delete d[t]:l.setRequestHeader(t,e)}),r.isUndefined(e.withCredentials)||(l.withCredentials=!!e.withCredentials),e.responseType)try{l.responseType=e.responseType}catch(t){if("json"!==e.responseType)throw t}"function"==typeof e.onDownloadProgress&&l.addEventListener("progress",e.onDownloadProgress),"function"==typeof e.onUploadProgress&&l.upload&&l.upload.addEventListener("progress",e.onUploadProgress),e.cancelToken&&e.cancelToken.promise.then(function(e){l&&(l.abort(),f(e),l=null)}),void 0===p&&(p=null),l.send(p)})}},function(e,t,n){"use strict";var r=n(14);e.exports=function(e,t,n){var o=n.config.validateStatus;!o||o(n.status)?e(n):t(r("Request failed with status code "+n.status,n.config,null,n.request,n))}},function(e,t,n){"use strict";var r=n(15);e.exports=function(e,t,n,o,i){var s=new Error(e);return r(s,t,n,o,i)}},function(e,t){"use strict";e.exports=function(e,t,n,r,o){return e.config=t,n&&(e.code=n),e.request=r,e.response=o,e.isAxiosError=!0,e.toJSON=function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:this.config,code:this.code}},e}},function(e,t,n){"use strict";var r=n(17),o=n(18);e.exports=function(e,t){return e&&!r(t)?o(e,t):t}},function(e,t){"use strict";e.exports=function(e){return/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(e)}},function(e,t){"use strict";e.exports=function(e,t){return t?e.replace(/\/+$/,"")+"/"+t.replace(/^\/+/,""):e}},function(e,t,n){"use strict";var r=n(2),o=["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"];e.exports=function(e){var t,n,i,s={};return e?(r.forEach(e.split("\n"),function(e){if(i=e.indexOf(":"),t=r.trim(e.substr(0,i)).toLowerCase(),n=r.trim(e.substr(i+1)),t){if(s[t]&&o.indexOf(t)>=0)return;"set-cookie"===t?s[t]=(s[t]?s[t]:[]).concat([n]):s[t]=s[t]?s[t]+", "+n:n}}),s):s}},function(e,t,n){"use strict";var r=n(2);e.exports=r.isStandardBrowserEnv()?function(){function e(e){var t=e;return n&&(o.setAttribute("href",t),t=o.href),o.setAttribute("href",t),{href:o.href,protocol:o.protocol?o.protocol.replace(/:$/,""):"",host:o.host,search:o.search?o.search.replace(/^\?/,""):"",hash:o.hash?o.hash.replace(/^#/,""):"",hostname:o.hostname,port:o.port,pathname:"/"===o.pathname.charAt(0)?o.pathname:"/"+o.pathname}}var t,n=/(msie|trident)/i.test(navigator.userAgent),o=document.createElement("a");return t=e(window.location.href),function(n){var o=r.isString(n)?e(n):n;return o.protocol===t.protocol&&o.host===t.host}}():function(){return function(){return!0}}()},function(e,t,n){"use strict";var r=n(2);e.exports=r.isStandardBrowserEnv()?function(){return{write:function(e,t,n,o,i,s){var a=[];a.push(e+"="+encodeURIComponent(t)),r.isNumber(n)&&a.push("expires="+new Date(n).toGMTString()),r.isString(o)&&a.push("path="+o),r.isString(i)&&a.push("domain="+i),s===!0&&a.push("secure"),document.cookie=a.join("; ")},read:function(e){var t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){}}}()},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){t=t||{};var n={},o=["url","method","params","data"],i=["headers","auth","proxy"],s=["baseURL","url","transformRequest","transformResponse","paramsSerializer","timeout","withCredentials","adapter","responseType","xsrfCookieName","xsrfHeaderName","onUploadProgress","onDownloadProgress","maxContentLength","validateStatus","maxRedirects","httpAgent","httpsAgent","cancelToken","socketPath"];r.forEach(o,function(e){"undefined"!=typeof t[e]&&(n[e]=t[e])}),r.forEach(i,function(o){r.isObject(t[o])?n[o]=r.deepMerge(e[o],t[o]):"undefined"!=typeof t[o]?n[o]=t[o]:r.isObject(e[o])?n[o]=r.deepMerge(e[o]):"undefined"!=typeof e[o]&&(n[o]=e[o])}),r.forEach(s,function(r){"undefined"!=typeof t[r]?n[r]=t[r]:"undefined"!=typeof e[r]&&(n[r]=e[r])});var a=o.concat(i).concat(s),u=Object.keys(t).filter(function(e){return a.indexOf(e)===-1});return r.forEach(u,function(r){"undefined"!=typeof t[r]?n[r]=t[r]:"undefined"!=typeof e[r]&&(n[r]=e[r])}),n}},function(e,t){"use strict";function n(e){this.message=e}n.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},n.prototype.__CANCEL__=!0,e.exports=n},function(e,t,n){"use strict";function r(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise(function(e){t=e});var n=this;e(function(e){n.reason||(n.reason=new o(e),t(n.reason))})}var o=n(23);r.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},r.source=function(){var e,t=new r(function(t){e=t});return{token:t,cancel:e}},e.exports=r},function(e,t){"use strict";e.exports=function(e){return function(t){return e.apply(null,t)}}}])}); 3 | //# sourceMappingURL=axios.min.map -------------------------------------------------------------------------------- /src/main/resources/static/js/bs4.pop.js: -------------------------------------------------------------------------------- 1 | let bs4pop = {}; 2 | 3 | (function(pop){ 4 | 5 | pop.dialog = function(opts){ 6 | 7 | opts = $.extend( true, { 8 | id: '',//'#xxx',对话框ID, 9 | title: '', 10 | content: '', //可以是 string、element,$object 11 | className: '', //自定义样式 12 | width: 300, 13 | height: '', 14 | target: 'body',//在什么dom内创建dialog 15 | 16 | closeBtn: true, //是否有关闭按钮 17 | hideRemove: true,//关闭时移除dom 18 | escape: true, //Esc 退出 19 | autoFocus: true,//初始化时自动获得焦点 20 | show: true,//是否在一开始时就显示对话框 21 | backdrop: true,//模态背景 true: 显示模态,false: 没有模态,'static': 显示模态,单击模态不关闭对话框 22 | btns: [], //footer按钮 [{label: 'Button', className: 'btn-primary',onClick(cb){}}] 23 | drag: true,//是否启用拖拽 24 | 25 | onShowStart(){}, 26 | onShowEnd(){}, 27 | onHideStart(){}, 28 | onHideEnd(){}, 29 | onClose(){}, 30 | }, opts); 31 | 32 | //得到 $el 33 | let $el = opts.id !== '' ? $('#'+opts.id) : undefined; 34 | if(!$el || !$el.length){ 35 | $el = $(` 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | `); 44 | } 45 | 46 | //得到 $body 47 | let $body = $el.find('.modal-body'); 48 | 49 | //创建 header 50 | if(opts.closeBtn || opts.title){ 51 | 52 | let $header = $(''); 53 | 54 | if(opts.title){ 55 | $header.append(` ${opts.title} `); 56 | } 57 | 58 | if(opts.closeBtn){ 59 | $header.append(` 60 | 61 | × 62 | 63 | `); 64 | } 65 | 66 | $body.before($header); 67 | 68 | } 69 | 70 | //创建 footer 71 | if(opts.btns.length){ 72 | 73 | let $footer = $(''); 74 | opts.btns.forEach(btn => { 75 | 76 | btn = $.extend(true, { 77 | label: 'Button', 78 | className: 'btn-primary', 79 | onClick(cb){}, 80 | }, btn); 81 | 82 | let $btn = $(''+btn.label+''); 83 | 84 | $btn.on('click', evt => { 85 | 86 | //提供手动关闭对话框的方法,以便于对话框延迟关闭 87 | evt.hide = ()=>{ 88 | $el.modal('hide'); 89 | }; 90 | 91 | //如果返回不是false就自动隐藏dialog 92 | if(btn.onClick(evt) !== false){ 93 | $el.modal('hide'); 94 | } 95 | 96 | }); 97 | 98 | $footer.append($btn); 99 | 100 | }); 101 | 102 | $body.after($footer); 103 | 104 | } 105 | 106 | //创建内容 107 | if(typeof opts.content === 'string'){ 108 | $body.html(opts.content); 109 | }else if(typeof opts.content === 'object'){ 110 | $body.empty(); 111 | $(opts.content).contents().appendTo($body);//移动dom到 modal-body下 112 | } 113 | 114 | //设置属性 115 | opts.id && $el.attr('id', opts.id); 116 | opts.className && $el.addClass(opts.className); 117 | opts.width && $el.find('.modal-dialog').width(opts.width).css('max-width', opts.width); 118 | opts.height && $el.find('.modal-dialog').height(opts.height); 119 | opts.isCenter && $el.find('.modal-dialog').addClass('modal-dialog-centered');//对话框屏幕居中 120 | 121 | //绑定事件 122 | opts.hideRemove && $el.on('hidden.bs.modal', function(){ 123 | $el.modal('dispose').remove();//移除dom 124 | }); 125 | $el.on('show.bs.modal', opts.onShowStart); 126 | $el.on('shown.bs.modal', opts.onShowEnd); 127 | $el.on('hide.bs.modal', opts.onHideStart); 128 | $el.on('hidden.bs.modal', opts.onHideEnd); 129 | opts.closeBtn && $el.find('.close').on('click', function(){ 130 | return opts.onClose(); 131 | }); 132 | 133 | $(opts.target).append($el); 134 | 135 | $el.modal({ 136 | backdrop: opts.backdrop, //boolean or the string 'static'.Includes a modal-backdrop element. Alternatively, specify static for a backdrop which doesn't close the modal on click. 137 | keyboard: opts.escape, //Closes the modal when escape key is pressed 138 | focus: opts.autoFocus, //Puts the focus on the modal when initialized. 139 | show: opts.show //Shows the modal when initialized. 140 | }); 141 | 142 | let result = { 143 | $el: $el, 144 | show(){ 145 | $el.modal('show'); 146 | }, 147 | hide(){ 148 | $el.modal('hide'); 149 | }, 150 | toggle(){ 151 | $el.modal('toggle'); 152 | }, 153 | destory(){ 154 | $el.modal('dispose'); 155 | } 156 | }; 157 | 158 | return result; 159 | 160 | }; 161 | 162 | pop.removeAll = function(){ 163 | $('[role="dialog"],.modal-backdrop').remove(); 164 | }; 165 | 166 | })(bs4pop); 167 | 168 | 169 | (function(pop){ 170 | // 消息框 171 | pop.notice = function(content, opts){ 172 | 173 | opts = $.extend( true, { 174 | 175 | type: 'primary', //primary, secondary, success, danger, warning, info, light, dark 176 | position: 'topcenter', //topleft, topcenter, topright, bottomleft, bottomcenter, bottonright, center, 177 | appendType: 'append', //append, prepend 178 | closeBtn: false, 179 | autoClose: 4000, 180 | className: '', 181 | 182 | }, opts); 183 | 184 | // 得到容器 $container 185 | let $container = $('#alert-container-'+ opts.position); 186 | if(!$container.length){ 187 | $container = $(''); 188 | $('body').append($container); 189 | } 190 | 191 | // alert $el 192 | let $el = $(` 193 | ${content} 194 | `); 195 | 196 | // 关闭按钮 197 | if(opts.autoClose){ 198 | $el 199 | .append(` 200 | 201 | × 202 | 203 | `) 204 | .addClass('alert-dismissible'); 205 | } 206 | 207 | //定时关闭 208 | if(opts.autoClose){ 209 | 210 | let t = setTimeout(() => { 211 | $el.alert('close'); 212 | }, opts.autoClose); 213 | 214 | } 215 | 216 | opts.appendType === 'append' ? $container.append($el) : $container.prepend($el); 217 | 218 | setTimeout(() => { 219 | $el.addClass('show'); 220 | }, 200); 221 | 222 | return; 223 | 224 | }; 225 | 226 | })(bs4pop); 227 | 228 | 229 | 230 | if( typeof module === "object" && typeof module.exports === "object" ){ 231 | module.exports = bs4pop 232 | } -------------------------------------------------------------------------------- /src/main/resources/static/js/click.js: -------------------------------------------------------------------------------- 1 | $("#select").click(function () { 2 | $("#upload").click(); 3 | }); 4 | 5 | // 将网址拷贝到剪贴板 6 | function clipboard(obj) { 7 | let node = $(obj).parent().parent().prev(); 8 | node.select(); 9 | document.execCommand("Copy"); 10 | bs4pop.notice("复制成功!", {position: "bottomright", type: "secondary"}); 11 | } -------------------------------------------------------------------------------- /src/main/resources/static/js/go.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | // 在页面第一次加载时设置dialog的位置 3 | setFocus(); 4 | 5 | // 每次浏览器尺寸发生改变 6 | $(window).resize(function() { 7 | setFocus(); 8 | }); 9 | 10 | // 点击上传后的选择窗口 11 | $("#selectButton").click(function() { 12 | $("#selectFile").fadeIn(500); 13 | // 内容 14 | $(".upload-file").show(); 15 | $(".clone-file").hide(); 16 | }); 17 | 18 | // 关闭窗口 19 | $(".dialog-close").click(function() { 20 | $("#selectFile").fadeOut(500); 21 | 22 | // 标题的效果 23 | $("#clone").removeClass("selected"); 24 | $("#cloneArea").val(""); 25 | $("#local-upload").addClass("selected"); 26 | $("#upload").val(""); 27 | }); 28 | 29 | // 点击url上传的效果 30 | $("#clone").click(function() { 31 | // 标题的效果 32 | $("#local-upload").removeClass("selected"); 33 | $("#clone").addClass("selected"); 34 | 35 | // 内容 36 | $(".upload-file").hide(); 37 | $(".clone-file").show(); 38 | 39 | // 清空input里选择的文件 40 | $("#upload")[0].value= ''; 41 | }); 42 | 43 | // 点击普通上传的效果 44 | $("#local-upload").click(function() { 45 | // 标题的效果 46 | $("#clone").removeClass("selected"); 47 | $("#local-upload").addClass("selected"); 48 | 49 | // 内容 50 | $(".upload-file").show(); 51 | $(".clone-file").hide(); 52 | }); 53 | }); -------------------------------------------------------------------------------- /src/main/resources/static/js/history/func.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | axios.get('/api/getAllPics') 3 | .then(function (response) { 4 | console.log("历史记录根据您的IP地址生成"); 5 | console.log(response); 6 | if (response.data.msg == "fail") { 7 | $(".ip").text("您的IP地址(" + response.data.data + ")"); 8 | $(".count").text("找到0条记录"); 9 | console.log("用户没有上传任何图片"); 10 | return; 11 | } 12 | $(".ip").text("您的IP地址(" + response.data.data[0].ip + ")"); 13 | $(".count").text("找到" + response.data.data.length + "条记录"); 14 | $.each(response.data.data, function(i, value) { 15 | let year = this.path.split("/")[1]; 16 | let date = this.path.split("/")[2]; 17 | let src = location.origin + "/uploadImages" + this.path; 18 | // filename path ip 19 | let img = $("" + year + "年" + date.split("-")[0] + "月" + date.split("-")[1] + "日"); 20 | $("#grid").append(img); 21 | console.log(img.html()); 22 | }); 23 | new GridScrollFx(document.getElementById( 'grid' ), { 24 | viewportFactor : 0.4 25 | } ); 26 | }) 27 | .catch(function (error) { 28 | console.log(error); 29 | }); 30 | }); -------------------------------------------------------------------------------- /src/main/resources/static/js/jquery.lazyload.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Lazy Load - jQuery plugin for lazy loading images 3 | * 4 | * Copyright (c) 2007-2013 Mika Tuupola 5 | * 6 | * Licensed under the MIT license: 7 | * http://www.opensource.org/licenses/mit-license.php 8 | * 9 | * Project home: 10 | * http://www.appelsiini.net/projects/lazyload 11 | * 12 | * Version: 1.9.3 13 | * 14 | */ 15 | 16 | (function($, window, document, undefined) { 17 | var $window = $(window); 18 | 19 | $.fn.lazyload = function(options) { 20 | var elements = this; 21 | var $container; 22 | var settings = { 23 | threshold : 0, 24 | failure_limit : 0, 25 | event : "scroll", 26 | effect : "show", 27 | container : window, 28 | data_attribute : "original", 29 | skip_invisible : true, 30 | appear : null, 31 | load : null, 32 | placeholder : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" 33 | }; 34 | 35 | function update() { 36 | var counter = 0; 37 | 38 | elements.each(function() { 39 | var $this = $(this); 40 | if (settings.skip_invisible && !$this.is(":visible")) { 41 | return; 42 | } 43 | if ($.abovethetop(this, settings) || 44 | $.leftofbegin(this, settings)) { 45 | /* Nothing. */ 46 | } else if (!$.belowthefold(this, settings) && 47 | !$.rightoffold(this, settings)) { 48 | $this.trigger("appear"); 49 | /* if we found an image we'll load, reset the counter */ 50 | counter = 0; 51 | } else { 52 | if (++counter > settings.failure_limit) { 53 | return false; 54 | } 55 | } 56 | }); 57 | 58 | } 59 | 60 | if(options) { 61 | /* Maintain BC for a couple of versions. */ 62 | if (undefined !== options.failurelimit) { 63 | options.failure_limit = options.failurelimit; 64 | delete options.failurelimit; 65 | } 66 | if (undefined !== options.effectspeed) { 67 | options.effect_speed = options.effectspeed; 68 | delete options.effectspeed; 69 | } 70 | 71 | $.extend(settings, options); 72 | } 73 | 74 | /* Cache container as jQuery as object. */ 75 | $container = (settings.container === undefined || 76 | settings.container === window) ? $window : $(settings.container); 77 | 78 | /* Fire one scroll event per scroll. Not one scroll event per image. */ 79 | if (0 === settings.event.indexOf("scroll")) { 80 | $container.bind(settings.event, function() { 81 | return update(); 82 | }); 83 | } 84 | 85 | this.each(function() { 86 | var self = this; 87 | var $self = $(self); 88 | 89 | self.loaded = false; 90 | 91 | /* If no src attribute given use data:uri. */ 92 | if ($self.attr("src") === undefined || $self.attr("src") === false) { 93 | if ($self.is("img")) { 94 | $self.attr("src", settings.placeholder); 95 | } 96 | } 97 | 98 | /* When appear is triggered load original image. */ 99 | $self.one("appear", function() { 100 | if (!this.loaded) { 101 | if (settings.appear) { 102 | var elements_left = elements.length; 103 | settings.appear.call(self, elements_left, settings); 104 | } 105 | $("") 106 | .bind("load", function() { 107 | 108 | var original = $self.attr("data-" + settings.data_attribute); 109 | $self.hide(); 110 | if ($self.is("img")) { 111 | $self.attr("src", original); 112 | } else { 113 | $self.css("background-image", "url('" + original + "')"); 114 | } 115 | $self[settings.effect](settings.effect_speed); 116 | 117 | self.loaded = true; 118 | 119 | /* Remove image from array so it is not looped next time. */ 120 | var temp = $.grep(elements, function(element) { 121 | return !element.loaded; 122 | }); 123 | elements = $(temp); 124 | 125 | if (settings.load) { 126 | var elements_left = elements.length; 127 | settings.load.call(self, elements_left, settings); 128 | } 129 | }) 130 | .attr("src", $self.attr("data-" + settings.data_attribute)); 131 | } 132 | }); 133 | 134 | /* When wanted event is triggered load original image */ 135 | /* by triggering appear. */ 136 | if (0 !== settings.event.indexOf("scroll")) { 137 | $self.bind(settings.event, function() { 138 | if (!self.loaded) { 139 | $self.trigger("appear"); 140 | } 141 | }); 142 | } 143 | }); 144 | 145 | /* Check if something appears when window is resized. */ 146 | $window.bind("resize", function() { 147 | update(); 148 | }); 149 | 150 | /* With IOS5 force loading images when navigating with back button. */ 151 | /* Non optimal workaround. */ 152 | if ((/(?:iphone|ipod|ipad).*os 5/gi).test(navigator.appVersion)) { 153 | $window.bind("pageshow", function(event) { 154 | if (event.originalEvent && event.originalEvent.persisted) { 155 | elements.each(function() { 156 | $(this).trigger("appear"); 157 | }); 158 | } 159 | }); 160 | } 161 | 162 | /* Force initial check if images should appear. */ 163 | $(document).ready(function() { 164 | update(); 165 | }); 166 | 167 | return this; 168 | }; 169 | 170 | /* Convenience methods in jQuery namespace. */ 171 | /* Use as $.belowthefold(element, {threshold : 100, container : window}) */ 172 | 173 | $.belowthefold = function(element, settings) { 174 | var fold; 175 | 176 | if (settings.container === undefined || settings.container === window) { 177 | fold = (window.innerHeight ? window.innerHeight : $window.height()) + $window.scrollTop(); 178 | } else { 179 | fold = $(settings.container).offset().top + $(settings.container).height(); 180 | } 181 | 182 | return fold <= $(element).offset().top - settings.threshold; 183 | }; 184 | 185 | $.rightoffold = function(element, settings) { 186 | var fold; 187 | 188 | if (settings.container === undefined || settings.container === window) { 189 | fold = $window.width() + $window.scrollLeft(); 190 | } else { 191 | fold = $(settings.container).offset().left + $(settings.container).width(); 192 | } 193 | 194 | return fold <= $(element).offset().left - settings.threshold; 195 | }; 196 | 197 | $.abovethetop = function(element, settings) { 198 | var fold; 199 | 200 | if (settings.container === undefined || settings.container === window) { 201 | fold = $window.scrollTop(); 202 | } else { 203 | fold = $(settings.container).offset().top; 204 | } 205 | 206 | return fold >= $(element).offset().top + settings.threshold + $(element).height(); 207 | }; 208 | 209 | $.leftofbegin = function(element, settings) { 210 | var fold; 211 | 212 | if (settings.container === undefined || settings.container === window) { 213 | fold = $window.scrollLeft(); 214 | } else { 215 | fold = $(settings.container).offset().left; 216 | } 217 | 218 | return fold >= $(element).offset().left + settings.threshold + $(element).width(); 219 | }; 220 | 221 | $.inviewport = function(element, settings) { 222 | return !$.rightoffold(element, settings) && !$.leftofbegin(element, settings) && 223 | !$.belowthefold(element, settings) && !$.abovethetop(element, settings); 224 | }; 225 | 226 | /* Custom selectors for your convenience. */ 227 | /* Use as $("img:below-the-fold").something() or */ 228 | /* $("img").filter(":below-the-fold").something() which is faster */ 229 | 230 | $.extend($.expr[":"], { 231 | "below-the-fold" : function(a) { return $.belowthefold(a, {threshold : 0}); }, 232 | "above-the-top" : function(a) { return !$.belowthefold(a, {threshold : 0}); }, 233 | "right-of-screen": function(a) { return $.rightoffold(a, {threshold : 0}); }, 234 | "left-of-screen" : function(a) { return !$.rightoffold(a, {threshold : 0}); }, 235 | "in-viewport" : function(a) { return $.inviewport(a, {threshold : 0}); }, 236 | /* Maintain BC for couple of versions. */ 237 | "above-the-fold" : function(a) { return !$.belowthefold(a, {threshold : 0}); }, 238 | "right-of-fold" : function(a) { return $.rightoffold(a, {threshold : 0}); }, 239 | "left-of-fold" : function(a) { return !$.rightoffold(a, {threshold : 0}); } 240 | }); 241 | 242 | })(jQuery, window, document); 243 | -------------------------------------------------------------------------------- /src/main/resources/static/js/main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 获取悬浮窗的焦点 3 | * 将它设置在窗口的中心点 4 | */ 5 | function setFocus() { 6 | var clientHeight = $(document.body).height(); 7 | var clientWidth = $(document.body).width(); 8 | 9 | 10 | var secWidth = $("#selectFile").width() 11 | var secHeight = $("#selectFile").height(); 12 | 13 | var left = (clientWidth/2) - (secWidth/2); 14 | var top = (clientHeight/2) - (secHeight/2); 15 | 16 | $("#selectFile").css("left", left); 17 | $("#selectFile").css("top", top); 18 | } 19 | 20 | 21 | /** 22 | * 获取上传文件对象 23 | */ 24 | function upload() { 25 | if ($(".selected").text() == "本地上传") { 26 | // 直接选择图片时 27 | var fileCount = $("#upload")[0].files.length; 28 | console.log(fileCount); 29 | for (var i = 0; i < fileCount; i++) { 30 | let file = ($("#upload")[0].files[i]); 31 | uploadFile(file, (res) =>{ 32 | let loaded = res.loaded, 33 | total = res.total; 34 | 35 | console.log("loaded: " + loaded); 36 | console.log("total: " + total); 37 | $("#test").css("width", loaded/total * 100 + "%"); 38 | },(res) =>{ 39 | switch (res.data.state) { 40 | case "ok" : 41 | let instance = generateInstance(res.data.ext, location.origin + res.data.msg); 42 | $(".progress").after(instance); 43 | instance.slideDown(1000); 44 | bs4pop.notice("一张图片已上传成功!", {position: "bottomright", type: "secondary"}); 45 | $("#test").animate({width:'0%'}); 46 | break; 47 | case "!pic" : 48 | bs4pop.notice("请上传图片文件!", {position: "bottomright", type: "secondary"}); 49 | break; 50 | case "error" : 51 | bs4pop.notice("上传错误,请重新上传!", {position: "bottomright", type: "secondary"}); 52 | break; 53 | case "null" : 54 | break; 55 | case "!admin" : 56 | bs4pop.notice(res.data.msg, {position: "bottomright", type: "secondary"}); 57 | break; 58 | } 59 | $(".progress-bar").css("width", "0%") 60 | }); 61 | } 62 | $(".dialog-close").click(); 63 | } else { 64 | // 获取输入框里的地址 65 | var url = $("#cloneArea").val(); 66 | 67 | // 判断是否为空 68 | if (url == "") { 69 | console.log("没有输入任何网址"); 70 | console.log("无法clone"); 71 | return; 72 | } else { 73 | $(".remind").text("准备传输,请稍后"); 74 | // 将输入框里的内容按行分开 75 | let urls = url.split("\n"); 76 | // 使用for in 77 | for (let i in urls) { 78 | console.log(urls[i]); 79 | clone(urls[i]); 80 | } 81 | } 82 | $(".dialog-close").click(); 83 | } 84 | } 85 | 86 | /** 87 | * 向服务器上传文件 88 | */ 89 | function uploadFile(file, callback1, callback2) { 90 | let param = new FormData(); 91 | param.append("file", file); 92 | axios({ 93 | method: 'post', 94 | url: '/upload', 95 | data: param, 96 | onUploadProgress: function(progressEvent) { 97 | callback1(progressEvent); 98 | } 99 | }) 100 | .then(function (response) { 101 | callback2(response); 102 | }) 103 | .catch(function (error) { 104 | console.log(error); 105 | }); 106 | } 107 | 108 | /** 109 | * 将输入框内的url地址提交给服务器 110 | */ 111 | function clone(str) { 112 | $(".remind").text("正在克隆图片......"); 113 | axios({ 114 | method: 'post', 115 | url: '/clone', 116 | data: { 117 | "url": str 118 | } 119 | }) 120 | .then(function (response) { 121 | switch (response.data.state) { 122 | case "ok" : 123 | let instance = generateInstance(response.data.org, location.origin + response.data.msg); 124 | $(".progress").after(instance); 125 | instance.slideDown(1000); 126 | bs4pop.notice("一张图片已上传成功!", {position: "bottomright", type: "secondary"}); 127 | $("#test").animate({width:'0%'}); 128 | $(".remind").text("克隆成功!"); 129 | break; 130 | case "!pic" : 131 | bs4pop.notice(response.data.msg, {position: "bottomright", type: "secondary"}); 132 | $(".remind").text("克隆失败,请输入图片地址"); 133 | break; 134 | case "error" : 135 | bs4pop.notice(response.data.msg, {position: "bottomright", type: "secondary"}); 136 | $(".remind").text("克隆错误,请重试"); 137 | break; 138 | case "repeat" : 139 | bs4pop.notice(response.data.msg, {position: "bottomright", type: "secondary"}); 140 | $(".remind").text("克隆失败,请重试"); 141 | break; 142 | case "!url" : 143 | bs4pop.notice(response.data.msg, {position: "bottomright", type: "secondary"}); 144 | $(".remind").text("克隆失败,请检查图片地址无误后重试"); 145 | break; 146 | case "!full" : 147 | bs4pop.notice(response.data.msg, {position: "bottomright", type: "secondary"}); 148 | $(".remind").text("克隆错误,地址有误"); 149 | case "!admin" : 150 | bs4pop.notice(response.data.msg, {position: "bottomright", type: "secondary"}); 151 | $(".remind").text("管理员已禁止克隆文件!"); 152 | } 153 | $(".progress-bar").css("width", "0%") 154 | }) 155 | .catch(function (error) { 156 | console.log(error); 157 | }); 158 | } 159 | 160 | 161 | function generateHtml(str) { 162 | return ""; 163 | } 164 | 165 | function generateMd(originalName, str) { 166 | return ''; 167 | } 168 | 169 | function generateInstance(orgName, str) { 170 | 171 | let instance = $(""); 172 | 173 | let instance_pic = $(""); 174 | 175 | let input_group = $(""); 176 | 177 | let input_http = $("HTTP复制"); 178 | input_http.children()[1].value = str; 179 | 180 | let input_html = $("HTML复制"); 181 | input_html.children()[1].value = generateHtml(str); 182 | 183 | let input_md = $("MARKDOWN复制"); 184 | input_md.children()[1].value = generateMd(orgName, str); 185 | 186 | instance_pic.appendTo(instance); 187 | 188 | 189 | input_http.appendTo(input_group); 190 | input_html.appendTo(input_group); 191 | input_md.appendTo(input_group); 192 | 193 | input_group.appendTo(instance); 194 | 195 | instance.css("display", "none"); 196 | 197 | return instance; 198 | } -------------------------------------------------------------------------------- /src/main/resources/templates/admin.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 管理 | 品格图床 | 免登陆图床 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 30 | 31 | 32 | 33 | 34 | 47 | 48 | 49 | 品格图床 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 上传 59 | 历史 60 | 管理 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | Administrator 73 | 74 | 75 | 76 | 登录 77 | 78 | 79 | 80 | 105 | 106 | 107 | 108 | 109 | 启用匿名用户上传图片 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 上传图片数量 121 | 122 | 123 | 124 | 张 125 | 126 | 127 | 128 | 129 | 130 | 131 | 服务器剩余容量 132 | 133 | 134 | 135 | GB 136 | 137 | 138 | 139 | 140 | 141 | 142 | 密码 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 当前图床版本 151 | 152 | 153 | 154 | 155 | 156 | 157 | 注销 158 | 修改 159 | 重载 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 182 | 183 | 184 | -------------------------------------------------------------------------------- /src/main/resources/templates/history.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 历史 | 品格图床 | 免登陆图床 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 49 | 50 | 51 | 60 | 61 | 62 | 品格图床 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 上传 72 | 历史 73 | 管理 74 | 75 | 76 | 77 | 78 | 81 | 82 | 历史记录根据您的IP地址生成,请及时保存 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 品格图床 | 免登陆图床 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 品格图床 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 上传 42 | 历史 43 | 管理 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 永久免费丨免登陆图床 54 | 请点击按钮上传 55 | 图片不会被压缩,不限制外链,永久保存 56 | 开发时长两年半的个人图床 57 | 58 | 图片大小限制: 59 | 已为用户保存: 张图片 60 | 服务器剩余空间: GB 61 | 62 | 63 | 选择文件 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 上传图片 76 | 77 | 78 | 79 | 本地上传 80 | URL上传 81 | 82 | 83 | 84 | 上传文件 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /src/test/java/paster/imagebed/Test.java: -------------------------------------------------------------------------------- 1 | package paster.imagebed; 2 | 3 | import paster.bean.History; 4 | import paster.utlis.HistoryTools; 5 | 6 | import java.util.List; 7 | 8 | public class Test { 9 | 10 | public static void main(String[] args) { 11 | 12 | // History history = HistoryTools.getHistory("10.1.1.1"); 13 | // List list = HistoryTools.allImg(history); 14 | // for (String s : list) { 15 | // System.out.println(s); 16 | // } 17 | 18 | System.out.println(HistoryTools.historyExist()); 19 | } 20 | } 21 | --------------------------------------------------------------------------------
启用匿名用户上传图片
历史记录根据您的IP地址生成,请及时保存
请点击按钮上传 55 | 图片不会被压缩,不限制外链,永久保存 56 | 开发时长两年半的个人图床
图片大小限制: 59 | 已为用户保存: 张图片 60 | 服务器剩余空间: GB
63 | 选择文件 64 | 65 |
上传图片