first commit
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="test"/>
|
||||
<classpathentry kind="lib" path="lib/zhiqim.jar" sourcepath="libsrc/zhiqim-src.jar"/>
|
||||
<classpathentry kind="lib" path="lib/zhiqim_zml.jar" sourcepath="libsrc/zhiqim_zml-src.jar"/>
|
||||
<classpathentry kind="lib" path="libext/zhiqim_manager.jar"/>
|
||||
<classpathentry kind="lib" path="libext/zhiqim_orm.jar"/>
|
||||
<classpathentry kind="lib" path="libext/zhiqim_sqlite3.8.6_native.jar"/>
|
||||
<classpathentry kind="lib" path="libext/zhiqim_ui.jar"/>
|
||||
<classpathentry kind="lib" path="libext/zhiqim_upload_large.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1,6 @@
|
||||
/bin
|
||||
/resource/file
|
||||
/database/zhiqim.db
|
||||
/database
|
||||
/uploadlarge
|
||||
/logs
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>zhiqim_httpd</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,2 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding/<project>=UTF-8
|
||||
@@ -0,0 +1,301 @@
|
||||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.codeComplete.argumentPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.argumentSuffixes=
|
||||
org.eclipse.jdt.core.codeComplete.fieldPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.fieldSuffixes=
|
||||
org.eclipse.jdt.core.codeComplete.localPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.localSuffixes=
|
||||
org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
|
||||
org.eclipse.jdt.core.codeComplete.staticFinalFieldPrefixes=
|
||||
org.eclipse.jdt.core.codeComplete.staticFinalFieldSuffixes=
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.7
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.7
|
||||
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
|
||||
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
|
||||
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
|
||||
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
|
||||
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
|
||||
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_switch=next_line
|
||||
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=next_line
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_header=false
|
||||
org.eclipse.jdt.core.formatter.comment.format_html=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
|
||||
org.eclipse.jdt.core.formatter.comment.format_source_code=true
|
||||
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=false
|
||||
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=do not insert
|
||||
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert
|
||||
org.eclipse.jdt.core.formatter.comment.line_length=80
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
|
||||
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
|
||||
org.eclipse.jdt.core.formatter.compact_else_if=true
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation=1
|
||||
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=1
|
||||
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
|
||||
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
|
||||
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
|
||||
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_empty_lines=false
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
|
||||
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
|
||||
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
|
||||
org.eclipse.jdt.core.formatter.indentation.size=4
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
|
||||
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
|
||||
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
|
||||
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
|
||||
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
|
||||
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
|
||||
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
|
||||
org.eclipse.jdt.core.formatter.lineSplit=160
|
||||
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
|
||||
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
|
||||
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
|
||||
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
|
||||
org.eclipse.jdt.core.formatter.tabulation.char=space
|
||||
org.eclipse.jdt.core.formatter.tabulation.size=4
|
||||
org.eclipse.jdt.core.formatter.use_on_off_tags=false
|
||||
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
|
||||
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
|
||||
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
|
||||
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
|
||||
Bestand-diff onderdrukt omdat een of meer regels te lang zijn
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. [http://fsf.org/]
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
@@ -0,0 +1,119 @@
|
||||
### 什么是“知启蒙WEB容器”?
|
||||
---------------------------------------
|
||||
“知启蒙WEB容器(zhiqim_httpd)”是Zhiqim Development Kit面向WEB开发的多例服务,提供更简洁配置、积木式组件模块和天然的模型模板设计,适用于各种大型负载均衡WEB服务群集、中小型组件模板化WEB工程和微型嵌入式HTTP/WEB服务。
|
||||
|
||||
<br>
|
||||
|
||||
### 知启蒙WEB容器的优点
|
||||
---------------------------------------
|
||||
1、ZhiqimHttpd仅依赖JDK1.7+和ZhiqimKernel、ZhiqimZML。15年自主研发和创新的坚持,值得信赖。<br>
|
||||
2、纯Java的WEB容器,比Tomcat/Jetty更轻量级的HTTP服务器,继承ZhiqimKernel的简洁配置和多例服务的能力。<br>
|
||||
3、抛弃Servlet/JSP规范,基于ZhiqimKernel/ZhiqimZML创新型的WEB容器规范,集成MVC/MVP架构,简单许多框架的学习成本。<br>
|
||||
4、在开发调试阶段,以ZhiqimKernel启动服务,无需依赖Tomcat/Jetty等容器,简化ZhiqimStudio/Eclipse中开发调试配置。<br>
|
||||
5、工程打包发布后,以ZhiqimKernel配置启动,只需配置JRE路径,简化Tomcat/Jetty/Jboss等学习成本和部署成本。<br>
|
||||
6、自主创新的积木式组件模型,提供包括数据库表、页面和功能一起打包的组件开发模式,更彻底的模块化解藕,使得大中型项目积木式搭建、众包协同成为可能。<br>
|
||||
7、适应复杂部署的能力,多端口监听、多服务配置、多虚拟目录配置、负载均衡、群集模式等(Nginx + 知启蒙WEB容器群集 + Redis)各种部署。<br>
|
||||
8、嵌入式WEB开发最佳应用,比JDK自带Http Server功能更完善,比Jetty等WEB容器更轻量简便。支持零配置注解方式和规约配置两种方案 <br>
|
||||
9、兼容Servet容器,通过zhiqim_servlet.jar适配到Tomcat/Jboss等容器中一样简单(不损耗知启蒙服务和知启蒙组件的支持),项目迁移影响极小。<br>
|
||||
<br>
|
||||
|
||||
|
||||
### 知启蒙WEB工程目录结构 <a href="https://github.com/zhiqim-com/V1.5.0/raw/master/ZhiqimExample/zhiqim_guestbook.zip">下载留言本示例</a>
|
||||
---------------------------------------
|
||||

|
||||
<br>
|
||||
|
||||
|
||||
### 知启蒙WEB容器简要配置说明
|
||||
---------------------------------------
|
||||
|
||||
```
|
||||
1、在[./conf/zhiqim.xml]的[config]项中增加多文件配置key=httpd,value=./conf/httpd.xml <br>
|
||||
2、在[./conf/zhiqim.xml]的[service]项中配置key=httpd,value=org.zhiqim.httpd.HttpServer的HTTP服务 <br>
|
||||
3、在[./conf/httpd.xml]文件中配置[httpd]项目中,并包括监听和上下文件环境的配置。<br>
|
||||
```
|
||||
|
||||
**一、[./conf/zhiqim.xml]配置如下:**
|
||||
|
||||
|
||||
```
|
||||
<group id="config" desc="系统其他配置文件,./开头表示工程相对路径下,绝对路径使用/或d:/等(Windows也使用顺斜杠作路径)">
|
||||
<item key="httpd" value="./conf/httpd.xml" update="false" desc="日志配置文件"/>
|
||||
</group>
|
||||
|
||||
<group id="service" desc="系统服务配置,有依赖时注意顺序,系统按顺序加载,按倒序销毁">
|
||||
<item key="httpd" value="org.zhiqim.httpd.HttpServer" update="false" desc="HTTP服务"/>
|
||||
</group>
|
||||
```
|
||||
|
||||
**二、[./conf/httpd.xml]配置如下:**
|
||||
|
||||
|
||||
```
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE ZHIQIM-CONFIG PUBLIC "-//ZHIQIM //DTD Zhiqim-Config Configuration 1.4.0//EN" "http://zhiqim.org/xmldtds/zhiqim_config_1_4_0.dtd">
|
||||
<zhiqim-config>
|
||||
|
||||
<group id="httpd" desc="HTTP服务">
|
||||
<item key="listen" value="httpd.listen" update="false" desc="HTTP服务的监听器" />
|
||||
<item key="context" value="httpd.root" update="false" desc="HTTP服务下包括的上下文环境,多个用逗号隔开" />
|
||||
</group>
|
||||
|
||||
<group id="httpd.listen" desc="HTTP监听器">
|
||||
<item key="scheme" value="HTTP" update="false" desc="HTTP或HTTPS协议" />
|
||||
<item key="port" value="80" update="false" desc="监听端口" />
|
||||
<item key="minPoolSize" value="5" update="false" desc="HTTP处理线程池最小值" />
|
||||
<item key="maxPoolSize" value="10" update="false" desc="HTTP处理线程池最大值" />
|
||||
</group>
|
||||
|
||||
<group id="httpd.root" desc="HTTP根上下文环境">
|
||||
<item key="path" value="/" update="false" desc="上下文环境路径,必填" />
|
||||
<item key="resourceType" value="directory" update="false" desc="资源目录类型classpath|directory,无资源时可不配置" />
|
||||
<item key="resourcePath" value="./resource" update="false" desc="资源目录,无资源时可不配置" />
|
||||
<item key="welcomeUrl" value="/index.htm" update="false" desc="欢迎页,无资源时可不配置,/开头" />
|
||||
</group>
|
||||
|
||||
</zhiqim-config>
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
### 知启蒙WEB容器上下文配置
|
||||
```
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE ZHIQIM-CONFIG PUBLIC "-//ZHIQIM //DTD Zhiqim-Config Configuration 1.5.0//EN" "http://zhiqim.org/xmldtds/zhiqim_context_1_5_0.dtd">
|
||||
<zhiqim-context>
|
||||
|
||||
<!-- 属性配置 -->
|
||||
<attribute name="系统引导程序" key="bootstrap" value="org.zhiqim.example.gbook.Bootstrap"/>
|
||||
|
||||
<!-- 拦截器 -->
|
||||
<interceptor name="检查管理员是否登录" key="chkLogin" class="org.zhiqim.example.gbook.interceptor.ChkAdminLogin"/>
|
||||
|
||||
<!-- sessionUser-->
|
||||
<sessionUser name="前端" path="*" class="org.zhiqim.example.gbook.SessionUser" />
|
||||
|
||||
<!-- 访客部分 -->
|
||||
<action name="首页" path="/index.htm" view="/zview/index.zml" class="org.zhiqim.example.gbook.action.IndexAction"/>
|
||||
<action name="留言" path="/leaveMessage.htm" view="/zview/leaveMessage.zml" redirect="/index.htm" class="org.zhiqim.example.gbook.action.LeaveMessageAction"/>
|
||||
|
||||
<!-- 管理员部分 -->
|
||||
<action name="管理员登录" path="/adminLogin.htm" view="/zview/adminLogin.zml" redirect="/adminList.htm" class="org.zhiqim.example.gbook.action.AdminLoginAction"/>
|
||||
<action name="管理员退出" path="/adminLogout.htm" redirect="/index.htm" class="org.zhiqim.example.gbook.action.AdminLogoutAction"/>
|
||||
|
||||
<action name="管理员首页" interceptor="chkLogin" path="/adminList.htm" view="/zview/adminList.zml" class="org.zhiqim.example.gbook.action.AdminListAction"/>
|
||||
<action name="管理员回复留言" interceptor="chkLogin" path="/adminReply.htm" view="/zview/adminReply.zml" redirect="/adminList.htm" class="org.zhiqim.example.gbook.action.AdminReplyAction"/>
|
||||
<action name="管理员删除留言" interceptor="chkLogin" path="/adminDelete.htm" redirect="/adminList.htm" class="org.zhiqim.example.gbook.action.AdminDeleteAction"/>
|
||||
|
||||
</zhiqim-context>
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
|
||||
### 知启蒙技术框架与交流
|
||||
---------------------------------------
|
||||
<br><br>
|
||||
QQ群:加入QQ交流群,请点击[【458171582】](https://jq.qq.com/?_wv=1027&k=5DWlB3b) <br><br>
|
||||
教程:欲知更多知启蒙WEB容器,[【请戳这里】](https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd/tutorial/index.htm)
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE ZHIQIM-CONFIG PUBLIC "-//ZHIQIM //DTD Zhiqim-Config Configuration 1.5.0//EN" "http://zhiqim.org/xmldtds/zhiqim_config_1_5_0.dtd">
|
||||
<zhiqim-config>
|
||||
|
||||
<group id="httpd" desc="HTTP服务">
|
||||
<item key="context" value="httpd.root" type="protected" desc="必须,HTTP服务下包括的上下文环境,多个用逗号隔开" />
|
||||
<item key="scheme" value="HTTP" type="protected" desc="HTTP或HTTPS协议" />
|
||||
<item key="port" value="80" type="private" desc="监听端口" />
|
||||
<item key="poMinSize" value="5" type="protected" desc="HTTP处理线程池最小值" />
|
||||
<item key="poMaxSize" value="10" type="protected" desc="HTTP处理线程池最大值" />
|
||||
</group>
|
||||
|
||||
<group id="httpd.root" desc="HTTP根上下文环境">
|
||||
<item key="path" value="/" type="protected" desc="必须,上下文环境路径" />
|
||||
<item key="resourceType" value="directory" type="protected" desc="资源目录类型classpath|directory" />
|
||||
<item key="resourcePath" value="./resource" type="protected" desc="资源目录" />
|
||||
<item key="welcomeUrl" value="index.htm" type="protected" desc="欢迎页" />
|
||||
</group>
|
||||
|
||||
<group id="manage" desc="HTTP服务">
|
||||
<item key="context" value="manage.root" type="protected" desc="必须,HTTP服务下包括的上下文环境,多个用逗号隔开" />
|
||||
<item key="scheme" value="HTTP" type="protected" desc="HTTP或HTTPS协议" />
|
||||
<item key="port" value="88" type="private" desc="监听端口" />
|
||||
<item key="poMinSize" value="5" type="protected" desc="HTTP处理线程池最小值" />
|
||||
<item key="poMaxSize" value="10" type="protected" desc="HTTP处理线程池最大值" />
|
||||
</group>
|
||||
|
||||
<group id="manage.root" desc="HTTP根上下文环境">
|
||||
<item key="path" value="/" type="protected" desc="必须,上下文环境路径" />
|
||||
<item key="resourceType" value="directory" type="protected" desc="资源目录类型classpath|directory" />
|
||||
<item key="resourcePath" value="./manage" type="protected" desc="资源目录" />
|
||||
<item key="welcomeUrl" value="index.htm" type="protected" desc="欢迎页" />
|
||||
</group>
|
||||
|
||||
</zhiqim-config>
|
||||
@@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE ZHIQIM-CONFIG PUBLIC "-//ZHIQIM //DTD Zhiqim-Config Configuration 1.5.0//EN" "http://zhiqim.org/xmldtds/zhiqim_config_1_5_0.dtd">
|
||||
<zhiqim-config>
|
||||
|
||||
<group id="httpd" desc="HTTP服务">
|
||||
<item key="context" value="httpd.root,httpd.manage" type="protected" desc="必须,HTTP服务下包括的上下文环境,多个用逗号隔开" />
|
||||
<item key="scheme" value="HTTP" type="protected" desc="必须,HTTP或HTTPS协议" />
|
||||
<item key="port" value="80" type="protected" desc="必须,监听端口" />
|
||||
<item key="io" value="NIO" type="protected" desc="可选,IO方式,BIO|NIO,默认NIO" />
|
||||
<item key="ipAddress" value="" type="protected" desc="监听的IP地址,未配置和为空表示全IP(0.0.0.0),可配置网卡IP地址" />
|
||||
<item key="soTimeout" value="60" type="protected" desc="读流数据超时时长,单位:秒,未配置缺省60秒" />
|
||||
<item key="soLinger" value="0" type="protected" desc="关闭连接时TIME_WAIT时长,单位:秒,未配置或小于等于0表示未开启(未开启缺省240秒(2ML)" />
|
||||
<item key="soIdleTime" value="53" type="protected" desc="HTTP连接最大保持时间,未配置缺省53秒" />
|
||||
<item key="poMinSize" value="5" type="protected" desc="HTTP处理线程池最小值,未配置缺省20" />
|
||||
<item key="poMaxSize" value="10" type="protected" desc="HTTP处理线程池最大值,未配置缺省200" />
|
||||
<item key="poIdleTime" value="600" type="protected" desc="HTTP处理线程最大空闲时间,未配置缺省600秒" />
|
||||
<item key="poMaxQueueSize" value="30" type="protected" desc="HTTP处理线程全部忙,等待的队列大小,未配置缺省poIdleTime的3倍" />
|
||||
<item key="accessLog" value="false" type="protected" desc="HTTP访问日志是否打印true|false,未配置缺省false,为true时还配合logging配置" />
|
||||
</group>
|
||||
|
||||
<group id="httpd.root" desc="HTTP根上下文环境">
|
||||
<item key="domain" value="" type="protected" desc="上下文环境对应的域名,多个逗号隔开" />
|
||||
<item key="path" value="/" type="protected" desc="必须,上下文环境路径" />
|
||||
<item key="resourceType" value="directory" type="protected" desc="资源目录类型classpath|directory" />
|
||||
<item key="resourcePath" value="./resource" type="protected" desc="资源目录" />
|
||||
<item key="welcomeUrl" value="/index.htm" type="protected" desc="欢迎页" />
|
||||
|
||||
<!-- 静态上下文可选配置 -->
|
||||
<item key="encoding" value="UTF-8" type="protected" desc="服务默认编码,未配置缺省UTF-8" />
|
||||
<item key="notFoundUrl" value="/index.htm" type="protected" desc="找不到页面时转到该页" />
|
||||
<item key="maxContentLength" value="8388608" type="protected" desc="支持的上传最大内容长度,默认8M" />
|
||||
<item key="chunkSize" value="1048576" type="protected" desc="分块大小,默认1M,最大2097152(2M),最小4096(4K)" />
|
||||
<item key="expires" value="3600" type="protected" desc="静态文件有效期,单位秒,默认3600" />
|
||||
<item key="filter" value="/zml/*,*.jsp" type="protected" desc="过滤访问,默认为空,匹配上的访问时返回403错误,多个用逗号隔开,如/zml/*" />
|
||||
|
||||
<!-- ZML上下文可选配置 -->
|
||||
<item key="pathExactPrior" value="true" type="protected" desc="路径精确优先还是组件循序,默认true表示精确优先" />
|
||||
<item key="zml.pattern" value="*.htm,*.zml" type="protected" desc="ZML模式,未配置缺省为*.htm,*.zml" />
|
||||
<item key="zml.soIdleTime" value="86400" type="protected" desc="ZML保持时长,单位:秒,未配置缺省24小时" />
|
||||
<item key="zml.poIdleTime" value="3600" type="protected" desc="ZML空闲时长,单位:秒,未配置缺省1小时" />
|
||||
<item key="cookie.use" value="true" type="protected" desc="是否使用cookie,默认为true" />
|
||||
<item key="cookie.domain" value="" type="protected" desc="保存cookie到指定域名,为空取访问时的域名" />
|
||||
<item key="cookie.port" value="" type="protected" desc="保存cookie到指定端口,为空和为0取访问时的端口" />
|
||||
<item key="cookie.path" value="" type="protected" desc="保存cookie到指定端口,为空等于path" />
|
||||
<item key="session.manager" value="org.zhiqim.httpd.sessioner.HashSessionManager" type="protected" desc="会话管理器,未配置缺省内置的HashSessionManager" />
|
||||
<item key="session.timeout" value="18000" type="protected" desc="会话超时时长,单位:秒,最小20秒,未配置缺省1800秒(30分钟)" />
|
||||
<item key="session.idName" value="jsessionid" type="protected" desc="cookie或redirect-url时的取sessionid的名称,未配置缺省jsessionid" />
|
||||
<item key="session.parameter" value="http://127.0.0.1:10180/service/rmi,sessioner,58fda2df" type="protected" desc="会话管理器的其他参数" />
|
||||
</group>
|
||||
|
||||
<group id="httpd.manage" desc="HTTP根上下文环境">
|
||||
<item key="domain" value="" type="protected" desc="上下文环境对应的域名,多个逗号隔开" />
|
||||
<item key="path" value="/admin" type="protected" desc="必须,上下文环境路径" />
|
||||
<item key="resourceType" value="directory" type="protected" desc="资源目录类型classpath|directory" />
|
||||
<item key="resourcePath" value="./manage" type="protected" desc="资源目录" />
|
||||
<item key="welcomeUrl" value="/index.htm" type="protected" desc="欢迎页" />
|
||||
|
||||
<!-- 静态上下文可选配置 -->
|
||||
<item key="encoding" value="UTF-8" type="protected" desc="服务默认编码,未配置缺省UTF-8" />
|
||||
<item key="notFoundUrl" value="/index.htm" type="protected" desc="找不到页面时转到该页" />
|
||||
<item key="maxContentLength" value="8388608" type="protected" desc="支持的上传最大内容长度,默认8M" />
|
||||
<item key="chunkSize" value="1048576" type="protected" desc="分块大小,默认1M,最大2097152(2M),最小4096(4K)" />
|
||||
<item key="expires" value="3600" type="protected" desc="静态文件有效期,单位秒,默认3600" />
|
||||
<item key="filter" value="/zml/*,*.jsp" type="protected" desc="过滤访问,默认为空,匹配上的访问时返回403错误,多个用逗号隔开,如/zml/*" />
|
||||
|
||||
<!-- ZML上下文可选配置 -->
|
||||
<item key="pathExactPrior" value="true" type="protected" desc="路径精确优先还是组件循序,默认true表示精确优先" />
|
||||
<item key="zml.pattern" value="*.htm,*.zml" type="protected" desc="ZML模式,未配置缺省为*.htm,*.zml" />
|
||||
<item key="zml.soIdleTime" value="86400" type="protected" desc="ZML保持时长,单位:秒,未配置缺省24小时" />
|
||||
<item key="zml.poIdleTime" value="3600" type="protected" desc="ZML空闲时长,单位:秒,未配置缺省1小时" />
|
||||
<item key="cookie.use" value="true" type="protected" desc="是否使用cookie,默认为true" />
|
||||
<item key="cookie.domain" value="" type="protected" desc="保存cookie到指定域名,为空取访问时的域名" />
|
||||
<item key="cookie.port" value="" type="protected" desc="保存cookie到指定端口,为空和为0取访问时的端口" />
|
||||
<item key="cookie.path" value="" type="protected" desc="保存cookie到指定端口,为空等于path" />
|
||||
<item key="session.manager" value="org.zhiqim.httpd.sessioner.HashSessionManager" type="protected" desc="会话管理器,未配置缺省内置的HashSessionManager" />
|
||||
<item key="session.timeout" value="18000" type="protected" desc="会话超时时长,单位:秒,最小20秒,未配置缺省1800秒(30分钟)" />
|
||||
<item key="session.idName" value="jsessionid" type="protected" desc="cookie或redirect-url时的取sessionid的名称,未配置缺省jsessionid" />
|
||||
<item key="session.parameter" value="" type="protected" desc="会话管理器的其他参数" />
|
||||
|
||||
<item key="upload.large.rootDir" value="./uploadlarge" type="protected" desc="大文件上传根目录" />
|
||||
</group>
|
||||
|
||||
</zhiqim-config>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE ZHIQIM-CONFIG PUBLIC "-//ZHIQIM //DTD Zhiqim-Config Configuration 1.5.0//EN" "http://zhiqim.org/xmldtds/zhiqim_config_1_5_0.dtd">
|
||||
<zhiqim-config>
|
||||
|
||||
<group id="httpd" desc="HTTP服务器">
|
||||
<item key="context" value="httpd.root" type="protected" desc="必须,HTTP服务下包括的上下文环境,多个用逗号隔开" />
|
||||
<item key="scheme" value="HTTP" type="protected" desc="HTTP或HTTPS协议" />
|
||||
<item key="port" value="80" type="protected" desc="监听端口" />
|
||||
<item key="poMinSize" value="5" type="protected" desc="HTTP处理线程池最小值" />
|
||||
<item key="poMaxSize" value="10" type="protected" desc="HTTP处理线程池最大值" />
|
||||
</group>
|
||||
|
||||
<group id="httpd.root" desc="HTTP根上下文环境">
|
||||
<item key="path" value="/" type="protected" desc="必须,上下文环境路径" />
|
||||
<item key="resourceType" value="directory" type="protected" desc="资源目录类型classpath|directory" />
|
||||
<item key="resourcePath" value="./resource" type="protected" desc="资源目录" />
|
||||
<item key="welcomeUrl" value="index.htm" type="protected" desc="欢迎页" />
|
||||
</group>
|
||||
|
||||
<group id="manage" desc="HTTP服务器">
|
||||
<item key="listen" value="httpd.listen" type="protected" desc="必须,HTTP服务的监听器" />
|
||||
<item key="listen.domain" value="www.fadfox.org" type="protected" desc="必须,HTTP服务的监听器" />
|
||||
<item key="context" value="manage.root" type="protected" desc="必须,HTTP服务下包括的上下文环境,多个用逗号隔开" />
|
||||
</group>
|
||||
|
||||
<group id="manage.root" desc="HTTP根上下文环境">
|
||||
<item key="path" value="/" type="protected" desc="必须,上下文环境路径" />
|
||||
<item key="resourceType" value="directory" type="protected" desc="资源目录类型classpath|directory" />
|
||||
<item key="resourcePath" value="./resource" type="protected" desc="资源目录" />
|
||||
<item key="welcomeUrl" value="index.htm" type="protected" desc="欢迎页" />
|
||||
</group>
|
||||
|
||||
</zhiqim-config>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE ZHIQIM-CONFIG PUBLIC "-//ZHIQIM //DTD Zhiqim-Config Configuration 1.5.0//EN" "http://zhiqim.org/xmldtds/zhiqim_config_1_5_0.dtd">
|
||||
<zhiqim-config>
|
||||
|
||||
<group id="httpd" desc="HTTP服务器">
|
||||
<item key="context" value="httpd.root,httpd.admin" type="protected" desc="必须,HTTP服务下包括的上下文环境,多个用逗号隔开" />
|
||||
<item key="scheme" value="HTTP" type="protected" desc="HTTP或HTTPS协议" />
|
||||
<item key="port" value="80" type="protected" desc="监听端口" />
|
||||
<item key="poMinSize" value="5" type="protected" desc="HTTP处理线程池最小值" />
|
||||
<item key="poMaxSize" value="10" type="protected" desc="HTTP处理线程池最大值" />
|
||||
</group>
|
||||
|
||||
<group id="httpd.root" desc="HTTP根上下文环境">
|
||||
<item key="path" value="/" type="protected" desc="必须,上下文环境路径" />
|
||||
<item key="resourceType" value="directory" type="protected" desc="资源目录类型classpath|directory" />
|
||||
<item key="resourcePath" value="./resource" type="protected" desc="资源目录" />
|
||||
<item key="welcomeUrl" value="/index.htm" type="protected" desc="欢迎页" />
|
||||
</group>
|
||||
|
||||
<group id="httpd.admin" desc="HTTP管理上下文环境">
|
||||
<item key="path" value="/admin" type="protected" desc="必须,上下文环境路径" />
|
||||
<item key="resourceType" value="directory" type="protected" desc="资源目录类型classpath|directory" />
|
||||
<item key="resourcePath" value="./admin" type="protected" desc="资源目录" />
|
||||
<item key="welcomeUrl" value="/index.htm" type="protected" desc="欢迎页" />
|
||||
</group>
|
||||
|
||||
</zhiqim-config>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE ZHIQIM-CONFIG PUBLIC "-//ZHIQIM //DTD Zhiqim-Config Configuration 1.5.0//EN" "http://zhiqim.org/xmldtds/zhiqim_config_1_5_0.dtd">
|
||||
<zhiqim-config>
|
||||
|
||||
<group id="httpd" desc="HTTP服务">
|
||||
<item key="context" value="httpd.root" type="protected" desc="HTTP服务下包括的上下文环境,多个用逗号隔开" />
|
||||
<item key="scheme" value="HTTPS" type="protected" desc="HTTP或HTTPS协议" />
|
||||
<item key="port" value="443" type="protected" desc="监听端口" />
|
||||
<item key="io" value="NIO" type="protected" desc="可选,IO方式NIO/BIO,默认NIO" />
|
||||
<item key="poMinSize" value="20" type="protected" desc="HTTP处理线程池最小值" />
|
||||
<item key="poMaxSize" value="50" type="protected" desc="HTTP处理线程池最大值" />
|
||||
<item key="soIdleTime" value="31" type="protected" desc="HTTP连接最大保持时间,未配置缺省71秒" />
|
||||
|
||||
<item key="keystorePath" value="./conf/https/t2018.zhiqim.com.jks" type="protected" desc="HTTPS时必须,SSL密钥文件路径" />
|
||||
<item key="keystorePass" value="zhiqim" type="protected" desc="HTTPS时必须,SSL密钥文件密码" />
|
||||
</group>
|
||||
|
||||
<group id="httpd.root" desc="HTTP根上下文环境">
|
||||
<item key="path" value="/" type="protected" desc="上下文环境路径,必填" />
|
||||
<item key="resourceType" value="directory" type="protected" desc="资源目录类型classpath|directory" />
|
||||
<item key="resourcePath" value="./resource" type="protected" desc="资源目录" />
|
||||
<item key="welcomeUrl" value="index.htm" type="protected" desc="欢迎页" />
|
||||
|
||||
<item key="upload.large.rootDir" value="./uploadlarge" type="protected" desc="大文件上传根目录" />
|
||||
</group>
|
||||
|
||||
</zhiqim-config>
|
||||
Binair bestand niet weergegeven.
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE ZHIQIM-CONFIG PUBLIC "-//ZHIQIM //DTD Zhiqim-Config Configuration 1.5.0//EN" "http://zhiqim.org/xmldtds/zhiqim_config_1_5_0.dtd">
|
||||
<zhiqim-config>
|
||||
|
||||
<group id="httpd" desc="HTTP服务">
|
||||
<item key="context" value="httpd.root" type="protected" desc="必须,HTTP服务下包括的上下文环境,多个用逗号隔开" />
|
||||
<item key="scheme" value="HTTPS" type="protected" desc="必须,HTTP或HTTPS协议" />
|
||||
<item key="port" value="443" type="protected" desc="必须,监听端口" />
|
||||
<item key="io" value="NIO" type="protected" desc="可选,IO方式,AIO|BIO|NIO,默认NIO" />
|
||||
<item key="ipAddress" value="" type="protected" desc="监听的IP地址,未配置和为空表示全IP(0.0.0.0),可配置网卡IP地址" />
|
||||
<item key="soTimeout" value="60" type="protected" desc="读流数据超时时长,单位:秒,未配置缺省60秒" />
|
||||
<item key="soLinger" value="0" type="protected" desc="关闭连接时TIME_WAIT时长,单位:秒,未配置或小于等于0表示未开启(未开启缺省240秒(2ML)" />
|
||||
<item key="poMinSize" value="5" type="protected" desc="HTTP处理线程池最小值,未配置缺省20" />
|
||||
<item key="poMaxSize" value="10" type="protected" desc="HTTP处理线程池最大值,未配置缺省200" />
|
||||
<item key="poMaxQueueSize" value="30" type="protected" desc="HTTP处理线程全部忙,等待的队列大小,未配置缺省poIdleTime的3倍" />
|
||||
<item key="poIdleTime" value="600" type="protected" desc="HTTP处理线程最大空闲时间,未配置缺省600秒" />
|
||||
<item key="accessLog" value="false" type="protected" desc="HTTP访问日志是否打印true|false,未配置缺省false,为true时还配合logging配置" />
|
||||
|
||||
<!-- 以下为HTTPS专用 -->
|
||||
<item key="keystorePath" value="./conf/https_all/keystore.jks" type="protected" desc="HTTPS时必须,SSL密钥文件路径" />
|
||||
<item key="keystorePass" value="123456" type="protected" desc="HTTPS时必须,SSL密钥文件密码" />
|
||||
<item key="truststorePath" value="./conf/https_all/trust.jks" type="protected" desc="SSL信任CA文件路径" />
|
||||
<item key="truststorePass" value="123456" type="protected" desc="SSL信任CA文件密码,当truststorePath有配置时该项必须" />
|
||||
<item key="clientAuth" value="false" type="protected" desc="是否需要客户端认证,未配置缺省false" />
|
||||
</group>
|
||||
|
||||
<group id="httpd.root" desc="HTTP根上下文环境">
|
||||
<item key="domain" value="" type="protected" desc="上下文环境对应的域名,多个逗号隔开" />
|
||||
<item key="path" value="/" type="protected" desc="必须,上下文环境路径" />
|
||||
<item key="resourceType" value="directory" type="protected" desc="资源目录类型classPath|directory" />
|
||||
<item key="resourcePath" value="./resource" type="protected" desc="资源目录" />
|
||||
<item key="welcomeUrl" value="index.htm" type="protected" desc="欢迎页" />
|
||||
<item key="notFoundUrl" value="index.htm" type="protected" desc="找不到页面时转到该页" />
|
||||
<item key="filter" value="/conf/*,/ftml/*" type="protected" desc="过滤访问,默认为空,匹配上的访问时返回403错误,多个用逗号隔开,如/conf/*" />
|
||||
<item key="encoding" value="UTF-8" type="protected" desc="服务默认编码,未配置缺省UTF-8" />
|
||||
|
||||
<!-- 以下为ZmlContext专用 -->
|
||||
<item key="useCookie" value="true" type="protected" desc="是否使用cookie,默认为true" />
|
||||
<item key="sessionManager" value="org.zhiqim.httpd.session.HashSessionManager" type="protected" desc="会话管理器,未配置缺省内置的HashSessionManager" />
|
||||
<item key="sessionTimeout" value="1800" type="protected" desc="会话超时时长,单位:秒,最小20秒,未配置缺省1800秒(30分钟)" />
|
||||
<item key="sessionIdName" value="jsessionid" type="protected" desc="cookie或redirect-url时的取sessionid的名称,未配置缺省jsessionid" />
|
||||
<item key="sessionParameter" value="" type="protected" desc="会话管理器的其他参数" />
|
||||
<item key="zml.pattern" value="*.htm,*.zml" type="protected" desc="ZML模式,未配置缺省为*.htm,*.ftm,*.ftml" />
|
||||
<item key="zml.soIdleTime" value="86400" type="protected" desc="ZML保持时长,单位:秒,未配置缺省24小时" />
|
||||
<item key="zml.poIdleTime" value="3600" type="protected" desc="ZML空闲时长,单位:秒,未配置缺省1小时" />
|
||||
</group>
|
||||
|
||||
</zhiqim-config>
|
||||
Binair bestand niet weergegeven.
Binair bestand niet weergegeven.
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE ZHIQIM-CONFIG PUBLIC "-//ZHIQIM //DTD Zhiqim-Config Configuration 1.5.0//EN" "http://zhiqim.org/xmldtds/zhiqim_config_1_5_0.dtd">
|
||||
<zhiqim-config>
|
||||
|
||||
<group id="httpd" desc="HTTP服务器">
|
||||
<item key="context" value="httpd.root" type="private" desc="HTTP服务下包括的上下文环境,多个用逗号隔开" />
|
||||
<item key="scheme" value="HTTPS" type="private" desc="HTTP或HTTPS协议" />
|
||||
<item key="port" value="443" type="private" desc="监听端口" />
|
||||
<item key="poMinSize" value="5" type="private" desc="HTTP处理线程池最小值" />
|
||||
<item key="poMaxSize" value="10" type="private" desc="HTTP处理线程池最大值" />
|
||||
|
||||
<item key="keystorePath" value="./conf/https_trust/keystore.jks" type="private" desc="SSL密钥文件路径" />
|
||||
<item key="keystorePass" value="123456" type="private" desc="SSL存储密钥" />
|
||||
<item key="truststorePath" value="./conf/https_trust/trust.jks" type="private" desc="SSL密钥文件路径" />
|
||||
<item key="truststorePass" value="123456" type="private" desc="SSL信任密钥" />
|
||||
<item key="clientAuth" value="false" type="private" desc="客户端认证" />
|
||||
</group>
|
||||
|
||||
<group id="httpd.root" desc="HTTP根上下文环境">
|
||||
<item key="path" value="/" type="private" desc="上下文环境路径,必填" />
|
||||
<item key="resourceType" value="directory" type="private" desc="资源目录类型classPath|directory" />
|
||||
<item key="resourcePath" value="./resource" type="private" desc="资源目录" />
|
||||
<item key="welcomeUrl" value="index.htm" type="private" desc="欢迎页" />
|
||||
</group>
|
||||
|
||||
</zhiqim-config>
|
||||
Binair bestand niet weergegeven.
Binair bestand niet weergegeven.
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE ZHIQIM-CONFIG PUBLIC "-//ZHIQIM //DTD Zhiqim-Config Configuration 1.5.0//EN" "http://zhiqim.org/xmldtds/zhiqim_config_1_5_0.dtd">
|
||||
<zhiqim-config>
|
||||
|
||||
<group id="logging" desc="日志配置">
|
||||
<item key="logging.info" value="debug-info" type="protected" desc="信息日志配置" />
|
||||
<item key="logging.error" value="error-fatal" type="protected" desc="错误日志配置" />
|
||||
<item key="logging.httpd" value="debug-fatal" type="protected" desc="HTTPD监听日志配置" />
|
||||
</group>
|
||||
|
||||
<group id="logging.info" desc="信息日志配置">
|
||||
<item key="console.out" value="true" type="protected" desc="是否输出到控制台" />
|
||||
<item key="file.out" value="true" type="protected" desc="是否输出到文件" />
|
||||
<item key="file.path" value="./logs/info.log" type="protected" desc="输出到文件路径" />
|
||||
</group>
|
||||
|
||||
<group id="logging.error" desc="错误日志配置">
|
||||
<item key="console.out" value="true" type="protected" desc="是否输出到控制台" />
|
||||
<item key="file.out" value="true" type="protected" desc="是否输出到文件" />
|
||||
<item key="file.path" value="./logs/error.log" type="protected" desc="输出到文件路径" />
|
||||
</group>
|
||||
|
||||
<group id="logging.httpd" desc="错误日志配置">
|
||||
<item key="must.name" value="httpd.listen" type="protected" desc="必须匹配日志名称,默认为空即不匹配" />
|
||||
<item key="file.out" value="true" type="protected" desc="是否输出到文件" />
|
||||
<item key="file.path" value="./logs/httpd.log" type="protected" desc="输出到文件路径" />
|
||||
</group>
|
||||
|
||||
</zhiqim-config>
|
||||
@@ -0,0 +1,12 @@
|
||||
[boot]
|
||||
name=ZhiqimHttpd
|
||||
version=1.2
|
||||
port=50080
|
||||
|
||||
[config]
|
||||
logging=./conf/logging.xml
|
||||
httpd=./conf/httpd.xml
|
||||
|
||||
[service]
|
||||
logging=com.zhiqim.kernel.logging.LogServer
|
||||
httpd=org.zhiqim.httpd.HttpServer
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE ZHIQIM-CONFIG PUBLIC "-//ZHIQIM //DTD Zhiqim-Config Configuration 1.5.0//EN" "http://zhiqim.org/xmldtds/zhiqim_config_1_5_0.dtd">
|
||||
<zhiqim-config>
|
||||
|
||||
<group id="boot" desc="系统启动配置">
|
||||
<item key="name" value="知启蒙WEB容器" type="protected" desc="系统名称" />
|
||||
<item key="version" value="V1.5.0" type="protected" desc="系统版本" />
|
||||
<item key="port" value="50080" type="private" desc="系统监听端口,用于启动监听和命令关闭工程" />
|
||||
</group>
|
||||
|
||||
<group id="config" desc="系统其他配置文件,./开头表示工程相对路径下,绝对路径使用/或d:/等(Windows也使用顺斜杠作路径)">
|
||||
<item key="httpd" value="./conf/http_all/httpd.xml" type="protected" desc="HTTP服务配置"/>
|
||||
<item key="logging" value="./conf/logging.xml" type="protected" desc="日志服务配置"/>
|
||||
</group>
|
||||
|
||||
<group id="service" desc="系统服务配置,有依赖时注意顺序,系统按顺序加载,按倒序销毁">
|
||||
<item key="logging" value="org.zhiqim.kernel.logging.LogServer" type="protected" desc="日志服务"/>
|
||||
<item key="orm" value="org.zhiqim.orm.ORMServer" type="protected" desc="数据库服务"/>
|
||||
<item key="httpd" value="org.zhiqim.httpd.HttpServer" type="protected" desc="HTTP服务"/>
|
||||
</group>
|
||||
|
||||
<group id="orm" desc="数据库映射服务">
|
||||
<item key="dbType" value="sqlite" type="protected" desc="数据库类型,支持oracle|mysql|mssql|hsql|sqlite" />
|
||||
<item key="driver" value="org.sqlite.JDBC" type="protected" desc="数据库驱动" />
|
||||
<item key="url" value="jdbc:sqlite:./database/zhiqim.db" type="protected" desc="数据库Url" />
|
||||
<item key="user" value="root" type="protected" desc="数据库用户名" />
|
||||
<item key="pass" value="root" type="private" desc="数据库密码" />
|
||||
<item key="minPoolSize" value="2" type="protected" desc="线程池最小值" />
|
||||
<item key="maxPoolSize" value="10" type="protected" desc="线程池最大值" />
|
||||
<item key="maxKeepTime" value="7001" type="protected" desc="每连接最大保持时长,大于该值将重建连接,单位秒" />
|
||||
</group>
|
||||
|
||||
</zhiqim-config>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<section name="zhiqim">
|
||||
<section name="ExportJar">
|
||||
<item value="./resource/file" key="excludeDirs"/>
|
||||
<item value="test" key="excludePackages"/>
|
||||
<item value="false" key="isDivided"/>
|
||||
<item value="true" key="isExportAndZipProject"/>
|
||||
<item value="true" key="isExportJavaSource"/>
|
||||
<item value="false" key="isIncludeJavaFile"/>
|
||||
<item value="zhiqim_httpd" key="jarName"/>
|
||||
<item value="D:/_gitcan/ZhiqimDK/zhiqim_httpd/document/metainfo" key="metaInfoPath"/>
|
||||
<item value="zhiqim_httpd_v1.5.0" key="projectSourceName"/>
|
||||
<item value="D:/_gitee/zhiqim/V1.5.0/ZhiqimDK" key="releasePath"/>
|
||||
</section>
|
||||
</section>
|
||||
@@ -0,0 +1,29 @@
|
||||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: ZhiqimHttpd
|
||||
Bundle-SymbolicName: zhiqim_httpd
|
||||
Bundle-Version: 1.5.0
|
||||
Export-Package: org.zhiqim.httpd,
|
||||
org.zhiqim.httpd.aio,
|
||||
org.zhiqim.httpd.bio,
|
||||
org.zhiqim.httpd.constants,
|
||||
org.zhiqim.httpd.context,
|
||||
org.zhiqim.httpd.context.annotation,
|
||||
org.zhiqim.httpd.context.config,
|
||||
org.zhiqim.httpd.context.core,
|
||||
org.zhiqim.httpd.context.extend,
|
||||
org.zhiqim.httpd.context.returns,
|
||||
org.zhiqim.httpd.context.rule,
|
||||
org.zhiqim.httpd.context.service,
|
||||
org.zhiqim.httpd.context.util,
|
||||
org.zhiqim.httpd.entities,
|
||||
org.zhiqim.httpd.nio,
|
||||
org.zhiqim.httpd.resources,
|
||||
org.zhiqim.httpd.sessioner,
|
||||
org.zhiqim.httpd.util,
|
||||
org.zhiqim.httpd.validate,
|
||||
org.zhiqim.httpd.validate.ones,
|
||||
org.zhiqim.httpd.validate.onex,
|
||||
org.zhiqim.httpd.validate.two
|
||||
Require-Bundle: zhiqim,zhiqim_ml
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
|
||||
@@ -0,0 +1,185 @@
|
||||
V1.0.1.R2014022701
|
||||
1)版本创建、整理
|
||||
2)版本内部发布测试
|
||||
3)内部测试完成,发布
|
||||
V1.0.4.R2014060901
|
||||
1)fadfox.jar调整了Stringx类路径,有影响,要求版本在V1.0.4R2014060901以上
|
||||
2)增加HttpSessionUser两个字段created和accessed
|
||||
V1.0.5.R2014071601
|
||||
1)fadfox.jar增加JSON功能和HTTPC功能,涉及到HTTPD要求调整
|
||||
2)增加foxpaper功能,对页面信息进行解析
|
||||
3)修改文件上传实现类HttpUpload为HttpUploader,以防止和httpclient中HttpUpload同名,不好理解
|
||||
V1.0.6.R2014081901
|
||||
1)增加fadtemplate模块
|
||||
2)调整StringBuffer成StringBuilder
|
||||
3)增加AjaxClass中响应的一种新模式,支持{"responseStatus":0,"responseText":"成功"}格式
|
||||
4)修改ErrorMsg和SuccessMsg不支持http://跳转问题
|
||||
5)修改_Var增加变量顺序为,如果没有局部作用域,放置到page作用域,如果有局部作用域,查询局部作用域列表有定义则赋值,否则则最内层局部作用域赋值
|
||||
V1.0.6.R2015011201
|
||||
1)fadfox.jar调整DateTimes类方法,有影响,要求版本在V1.0.6R2015011201以上;
|
||||
2)调整模板输出不支持空行
|
||||
3)支持默认flex读起跨域文件crossdomain.xml为none
|
||||
4)去除模板中Hmtlx,Stringx,Listx,Validatex的调用,因为Htmls,Strings,Lists,Validates已继承这几个类
|
||||
V1.0.6.R2015031401
|
||||
1)对context.xml的action的return参数改为redirect,重新定义return表示是否转向=true表示不处理template和redirect
|
||||
2)对ActionForward和FoxHandler作了一下调整,增加强制处理错误和成功信息的判断
|
||||
V1.0.7.R2015040901
|
||||
1)计划增加fadfox.js,统一版本到1.0.7
|
||||
2)支持ajax,window,tooltips,drag,input等
|
||||
v1.0.7.R2015042101
|
||||
1)修改AjaxClass中原来"未知错误"的BUG
|
||||
2)修改AjaxClass支持先判断class是不是Action,如果是直接取Action的单例
|
||||
3)发布fadfox_1.0.3R2015042101.js和对应的fadfox_ajax.js,fadfox_calendar.js,fadfox_dialog.js,fadfox_tooltip.js,fadfox_input.js等
|
||||
4)删除原来的successMsg.fox和errorMsg.fox的定义,直接在FoxHandler中处理
|
||||
5)Styles.bodyOverflowHidden改为Styles.htmlOverflowHidden,增加Styles.htmlOverflowScroll表示overflow-y:scroll
|
||||
V1.0.7.R2015052001
|
||||
1)修改AjaxClass支持对Interceptor中设置redirect,在fadfox_ajax.js中重定向
|
||||
2)增加request.setAttributeAjaxResult中responseStatus不支持小于0和不支持100-699之间
|
||||
V1.0.7.R2015052501
|
||||
1)支持多个配置*context.xml文件和多个宏*macro.ftl文件
|
||||
2)FVariable支持instance=new/global,global表示读取Global中的实例,这样可以保证单例
|
||||
V1.0.7.R2015060101
|
||||
1)修改HttpSessionUser原为interface,改为class
|
||||
V1.0.8R2015060901
|
||||
1)整理成V1.0.8
|
||||
2)增加组件的支持
|
||||
3)修改context.xml和格式,支持配置组件、宏定义和多个context.xml文件
|
||||
4)修改HttpAccessLog中目录创建,改成递归创建
|
||||
V1.0.8.R2015061701
|
||||
1)修改Scripts.isNumericLen()方法中的BUG
|
||||
2)在HttpSessionUser上增加参数列表,通过getValues,getValue,setValue,removeValue,hasValue进行管理
|
||||
V1.1.0.R2015072901
|
||||
1)修改cookie设置的BUG
|
||||
2)调整server,listner,支持虚拟主机的配置
|
||||
3)拆离template出来,成立新的项目fadfox_template.jar
|
||||
4)修改原*.fox为/service/*目录,方便nginx等对路径进行转化
|
||||
V1.1.0.R2015082501
|
||||
1)增加HttpResponse中的addCookie方法
|
||||
2)增加@RmiAnnotation,对RMIService和AjaxService进行改造
|
||||
3)根据fadfox.jar整理成该版本
|
||||
V1.1.1.R2015091401
|
||||
1)使用JDK1.7编译
|
||||
2)增加在RMI/AJAX时,先使用@ClassShortName检查是不是类简称
|
||||
V1.1.2.R2015093001
|
||||
1)要求使用V1.1.2版本的fadfox.jar
|
||||
2)删除Variable,Rule的配置,暂时没有删dtd的说明
|
||||
3)修改for调用方式,合并Documents到Xmlx中,删除dtd的说明,改为v1.1.0,增加forward
|
||||
V1.1.3.R2015112501
|
||||
1)整理版本,用于生产系统
|
||||
2)根据FTimer改动修改的版本
|
||||
3)修改fadfox_drag.js
|
||||
V1.1.3.R2016010701版本:
|
||||
1)修改查找Action顺序的BUG,改为按getContextListAll()进行查找
|
||||
2)修改fadfox_dialog.js中F.prompt方法中$input获取路径错误的BUG
|
||||
3)修改fadfox.js中Draggable中callback未传值时回调的BUG
|
||||
4)优化fadfox_drag.js
|
||||
5)修改fadfox.css中radio在IE浏览器中高度和背景为白色的BUG
|
||||
6)修改IE11,两次请求user_agent不同导致session无法保存问题
|
||||
V1.1.4.R2016020301
|
||||
1)春节前整理版本号
|
||||
2)修改fadfox_clipboard.js支持增加offsetLeft,offsetTop,offsetWidth,offsetHeight,background等属性
|
||||
3)修改fadfox.js对offsetLeftAbs,offsetTopAbs修改支持IE和chrome加边框
|
||||
V1.1.5.R2016050301
|
||||
1)把资源部分拆出到fadfox_res.jar中,方便和fadfox_servlet.jar共享
|
||||
V1.2.0.R2016072101版本:
|
||||
1)调整包名com.zhiqim.fadfox.fadhttpd为com.zhiqim.fadfox.httpd,原来的fadhttp不好理解,现在正式使用httpd作为该产品的名称
|
||||
2)调整包名com.zhiqim.fadfox.foxcontext为com.zhiqim.fadfox.httpd.context,表示context是httpd的一部分,原来分为两部分不好理解
|
||||
3)增加HttpConnection, HttpContext, HttpRequest,HttpResponse修改成接口
|
||||
4)调整原实现HttpConnection, HttpContext, HttpRequest,HttpResponse到bio包内,修改为HttpBioConnection等,为后续增加aio作准备
|
||||
5)增加HttpHeader、HttpSender和HttpBioHeader、HttpBioSender,用于静态文件时无需创建复制的HttpRequest和HttpResponse的session,cookie,parameter等
|
||||
6)调整包com.zhiqim.fadfox.http.context.validate到fadfox.jar中,并删除Validate类中的HttpRequest关联
|
||||
7)删除ActionForward文件,修改Action类的execute方法只有HttpRequest一个参数,ActionForward的功能并入到HttpRequest。HttpResponse不大常用,如果需要用,可以从request.getResponse获取。
|
||||
8)修改原FoxContext等命名为FtmlContext,统一使用Ftml命名,表示该上下文环境是FTML的上下文环境,原HttpContext改为StaticContext表示静态文件上下文环境
|
||||
9)增加Context的接口,为fadfox_httpd_servlet.jar作适配用,如果需要把工程放置到Tomcat等容器下,只需增加fadfox_httpd_servlet.jar即可
|
||||
10)增加@AnAction的支持,在Action类上,或SwitchAction的子类的方法上定义@AnAction,设置好actionPackage属性即可作到无需context.xml实现零配置,当然规约上还是要求context.xml的
|
||||
11)修改原@RmiInterceptor为@AnInterceptor,@RmiNotFilter为@AnFilterNot等。支持配置在类和方法上,当类上有时,方法上可以不需要定义,如果方法不需支持类的,则加上@AnInterceptorNot作为例外设置
|
||||
V1.2.1.R2016100801
|
||||
1)删除ActionExecutor和ViewExecutor,合并到FtmlExecutor
|
||||
2)修改原定义的viewExt配置为patternUrl,默认值修改为*.ftml,*.ftm,*.htm
|
||||
3)修改验证码/service/vcode.jpg的展示,调整验证码sessionName原为vcode,修改为_vode_
|
||||
4)增加action中配置include字段,用于嵌套模板
|
||||
V1.2.2.R2017010101
|
||||
1)配合fadfox.jar调整HashMap<String, Object>为FHashMapSO
|
||||
3)增加只提供RMI服务时无需配置resourceType,resourcePath
|
||||
4)全面调整配置文件中配置项的规范,包括修改serverName为listen.domain,并支持多个
|
||||
5)全面优化配置文件中加载顺序和管理,新增类FtmlConfig
|
||||
6)优化Attribute读取顺序,优先顶级配置,再次根context.ftml配置,再次根context.xml,再次组件context.xml
|
||||
7)优化Action读取顺序,优先根context.xml配置,再次根actionPackaget,再倒序循环组件
|
||||
8)控制断点续传后的文件访问时最大不超时8M
|
||||
9)删除AnStatic的支持
|
||||
10)修改sendRedirect时也写入sessionId到cookie
|
||||
V1.3.0.R2017022701
|
||||
1)调整验证码功能,默认高度和f-input相等28px
|
||||
2)增加request.setValidateConfirm和request.setValidateGray设置验证确认信息和是否提交变灰
|
||||
3)修改request中验证,默认非firefox变回不需要回退,firefox需要F && F.onload时才支持变灰
|
||||
4)修改AnInterceptor,AnInterceptorNot为AnIntercept,AnInterceptNot,预留AnInterceptor用于拦截器定义
|
||||
5)修改Session.getSessionValidateCode为Session.getSessionVerificationCode,单词VerificationCode更准确
|
||||
6)删除validateScript的变量支持,请使用request.getValidateScript()方法
|
||||
7)删除request.setAttributeNoHtmlFilter方法,修改request.setAttribute为不作过滤,过滤任务在模板中使用#{}
|
||||
8)修改响应头reason增加Urls.encodeUTF8(reason)
|
||||
9)增加/service/rmi和/service/ajax对表单方式的提交处理
|
||||
10)迁移/service/upload(原大文件断点续传)和FadfoxUploader组件中,并修改为/service/uploadlarge,同时调整修改原/service/uploadone为/service/upload
|
||||
11)修改SwitchAction,从V1.2.0开始三参数变一参数时的BUG
|
||||
V1.3.1.R2017052801
|
||||
1)修改Asserts.asserts为Asserts.as()方法,使用三目运算断言,防止断言为真时需要初始化无意义的断言失败字符串
|
||||
2)修改HttpRequest方法getSessionUser(Class<T>),增加<T extends HttpSessionUser>约束
|
||||
V1.3.2.R2017080501
|
||||
1)增加Chunked支持,配置最大2M/最小4K,采用chunked时暂不支持gzip
|
||||
2)修改大文件下载时浏览器停止、关闭导致SocketException时,错误日志没必要打印,影响业务定位问题
|
||||
3)修改RmiService针对form表单提交不作字段检查密码#号AJAX使用form表单时不能修改BUG
|
||||
4)修改context.ftml中的变量定义支持完整表达式,原来只支持原型表达式和变量表达式
|
||||
5)修改returnCloseDiaolog时,配置fadfox_res.jar作立即关闭,防止闪屏
|
||||
6)增加f-call-iframe的支持,通过iframe提交表单和访问URL,保障有出错信息时,本页面不变化。
|
||||
7)配合20170927的fadfox.jar版本,支持(F || window).alert
|
||||
8)修改f-call-iframe中form参数frameTarget为fCallFrame=true,formIndex为fFormIndex
|
||||
9)增加对话框中的请求识别,参数为fDialogFrame=true
|
||||
10)增加request.setContentTypeNoCharset方法,表明contentType只支持mimeType,不需要charset
|
||||
V1.3.3.R2017110601
|
||||
1)增加/service/rmi的处理中内置对象(context、session、sessionUser、log)的处理
|
||||
2)修改UploadService中文件上传时指定目录的BUG
|
||||
3)增加对Action方法上AnTransaction的检查
|
||||
4)修改request.addParam(String, String)为request.addParam(String, Object)
|
||||
V1.4.0.R2018010101
|
||||
1)正式启用ZhiqimHttpd名称,原所有Fadfox改为Zhiqim,原所有fadfox改为zhiqim,原所有FADFOX改为ZHIQIM,原com.zhiqim.fadfox改为org.zhiqim.kernel
|
||||
2)转移Scripts,Scriptx,Styles到org.zhiqim.httpd.util
|
||||
3)转移org.zhiqim.kernel.validate到org.zhiqim.httpd.validate
|
||||
4)优化returnFrame页面,这里不需要zhiqim.js的支持,取parent.Z
|
||||
5)转移bootstrap的处理,由原来在httpd.xml中配置,修改为在context.xml中配置,当前如果未配置取最后一个组件的bootstrap
|
||||
6)转移websocket的处理,由原来在httpd.xml中配置,修改为在context.xml中配置,组件内websocket配置独立,通过@AnAlias(protocol)对应websocket类
|
||||
7)增加对/zres/*的处理,表示组件内的资源文件,优先于context.xml的处理
|
||||
8)增加对HTTP上下文中的contextXml的配置
|
||||
9)增加上传时HttpUploader回传参数到cntParamMap中
|
||||
10)增加Scripts.doReloadParent等方法
|
||||
11)增加对成功和失败的消息判断
|
||||
12)整理对ZhiqimML的支持,统一使用ZML代替Template的定义
|
||||
13)增加getAttribute时,当为_Var支持ZmlVarRuntime运行时读数据
|
||||
14)修改一个监听对应的所有HttpServer都关闭的时候,没有关闭监听的BUG
|
||||
15)Class.forName修改成Classes.forName,防止ClassLoader不准确
|
||||
16)修改zhiqim_context.xml组件配置resourcePath为path,删除actionPackage,改在context.xml配置属性,类似于bootstrap和websocket的配置
|
||||
17)修改为只有根context才加载组件,组件不检查依赖组件
|
||||
18)修改HttpSender对非chunked时重设contentlength,FileResourceEntity,ClassResourceEntity设置contentlength
|
||||
19)增加request.isMicroMessager()判断是否是微信中的浏览器
|
||||
20)增加request.isMobile()对MicroMessager的判断,如果有,也认为是mobile
|
||||
21)增加request.getZhiqimClientType()和setAttribute("zhiqimClientType", "www":"mobile")方法
|
||||
22)修改ZmlContext中initContext方法中,config.create失败的情况下,退出程序
|
||||
23)增加HttpSessionManager中public List<HttpSessionUser> getSessionUserList(Class<?> clazz);public PageResult<HttpSessionUser> getSessionUserPage(int pageNo, int pageSize, Class<?> clazz);方法
|
||||
24)增加对isMobile时zhiqim.mobile.css/js的检查,修改action加载时出错未退出工程的BUG
|
||||
25)修改if (F && Z.onload)的判断未改到的F的BUG
|
||||
V1.4.1.R2018052801
|
||||
1)增加静态文件过期时长配置expire
|
||||
2)增加cookie.domain/cookie.port/cookie.path的配置,以支持虚拟目录/子域名使用相同的COOKIE
|
||||
3)修改配置命名useCookie修改为cookie.use,matchType修改为pathExactPrior,sessionManager/sessionIdName/sessionTimeout/sessionParameter修改为session.manager/session.idName/session.timeout/session.parameter
|
||||
V1.5.0.R2019010101
|
||||
1)修改工程名为zhiqim_httpd,采用zhiqim_kernel_v1.5.0_r2019010101库
|
||||
2)修改默认配置文件名为/conf/config.xml和/conf/config.zml
|
||||
3)增加配置文件中sessionUser列表,和action中增加tips,sessionUser项,修改alert为success
|
||||
4)增加request.getParameterMatch(index)对应的方法
|
||||
5)删除AIO的处理方式,整理BIO/NIO公共方法到抽象类中,默认BIO,使用Nginx作代理时,建议配置成BIO,因为Nginx默认采用HTTP/1.0协议
|
||||
6)全面优化websocket在BIO/NIO三种IO下的处理方式
|
||||
7)修改request.getSessionUser()当session中只有一个sessionUser时返回该值,多个时返回null
|
||||
8)修改action,允许不指定sessionUser,默认取只有一个sessionUser的情况,多个时抛异常
|
||||
9)增加加载config.xml时异常抛出异常和文件路径
|
||||
10)整理HttpRequest/HttpResponse公开的方法,修改BIO合并NIO时的未关闭连接的BUG
|
||||
11)修复HttpWebsocketMessage/HttpWebsocketMessageAsync中的对mask=false的BUG和length可能为0时isClose无内部的BUG
|
||||
12)修改为Threadx处理方式,修改Tasker的继承为实现Task,定时任务Timer/Every改为Interval等
|
||||
13)执行程序和源码分开打包
|
||||
@@ -0,0 +1 @@
|
||||
1.
|
||||
Binair bestand niet weergegeven.
Binair bestand niet weergegeven.
Binair bestand niet weergegeven.
Binair bestand niet weergegeven.
Binair bestand niet weergegeven.
Binair bestand niet weergegeven.
Binair bestand niet weergegeven.
Binair bestand niet weergegeven.
Binair bestand niet weergegeven.
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE ZHIQIM-CONTEXT PUBLIC "-//ZHIQIM //DTD Zhiqim-Context Configuration 1.5.0//EN" "http://zhiqim.org/xmldtds/zhiqim_context_1_5_0.dtd">
|
||||
<zhiqim-context>
|
||||
|
||||
<!-- 属性 -->
|
||||
<attribute name="系统名称" key="name" value="知启蒙WEB容器" />
|
||||
<attribute name="系统版本" key="version" value="V1.5.0" />
|
||||
|
||||
<!-- Action -->
|
||||
<action name="模糊匹配" path="/abc/*" view="/zview/abc.zml" />
|
||||
|
||||
</zhiqim-context>
|
||||
@@ -0,0 +1,3 @@
|
||||
<#--变量定义-->
|
||||
<#var abc="context.zmlfff22333"/>
|
||||
<#var abcd="context.zml"/>
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>${context.getContextName()}</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
||||
<meta name="Author" content="${context.getContextName()}" />
|
||||
<script>
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
${abc}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
hi,abc
|
||||
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>${context.getContextName()}</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
||||
<meta name="Author" content="${context.getContextName()}" />
|
||||
<script>
|
||||
var isClose = true;
|
||||
var ws = new WebSocket("ws://127.0.0.1");
|
||||
ws.onopen = function()
|
||||
{
|
||||
function send()
|
||||
{
|
||||
console.log("中文");
|
||||
ws.send("中文");
|
||||
};
|
||||
|
||||
console.log("open");
|
||||
isClose = false;
|
||||
ws.send("开始...");
|
||||
F.timer(1000, 10, null, send);
|
||||
};
|
||||
ws.onmessage = function(e) { console.log(e.data); };
|
||||
ws.onclose = function(e) { console.log("WebSocketClosed!"); };
|
||||
ws.onerror = function(e) { console.log("WebSocketError!"); };
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
ddffdds在在在
|
||||
${abc}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE ZHIQIM-CONTEXT PUBLIC "-//ZHIQIM //DTD Zhiqim-Context Configuration 1.5.0//EN" "http://zhiqim.org/xmldtds/zhiqim_context_1_5_0.dtd">
|
||||
<zhiqim-context>
|
||||
|
||||
<!-- 组件配置 -->
|
||||
<component name="管理台" path="/org/zhiqim/manager/resource"/>
|
||||
<component name="大文件上传" path="/org/zhiqim/uploadlarge/resource"/>
|
||||
|
||||
<!-- 属性配置 -->
|
||||
<attribute name="系统名称" key="name" value="知启蒙公告"/>
|
||||
<attribute name="系统版本" key="version" value="V1.4.0"/>
|
||||
<attribute name="公告Socket" key="websocket" value="org.zhiqim.announcement.ZoaAnnouncementWS"/>
|
||||
<attribute name="公告路径" key="zhiqim_announcement" value="announcement"/>
|
||||
|
||||
<!-- 公告信息 -->
|
||||
<action name="公告列表" interceptor="chkZmrLogin" path="/${zhiqim_announcement}/announcement.htm" view="/ztmpl/zhiqim_manager/template.htm" include="/zview/zhiqim_announcement/announcement.zml" class="org.zhiqim.announcement.action.AnnouncementAction"/>
|
||||
<action name="增加公告页面" interceptor="chkZmrLogin" path="/${zhiqim_announcement}/announcementAdd.htm" view="/ztmpl/zhiqim_manager/template.htm" include="/zview/zhiqim_announcement/announcementAdd.zml" class="org.zhiqim.announcement.action.AnnouncementAction" method="add"/>
|
||||
<action name="增加公告处理" interceptor="chkZmrLogin" path="/${zhiqim_announcement}/announcementInsert.htm" redirect="/${zhiqim_announcement}/announcement.htm" success="增加成功" class="org.zhiqim.announcement.action.AnnouncementAction" method="insert"/>
|
||||
<action name="删除公告处理" interceptor="chkZmrLogin" path="/${zhiqim_announcement}/announcementDelete.htm" redirect="/${zhiqim_announcement}/announcement.htm" success="删除成功" class="org.zhiqim.announcement.action.AnnouncementAction" method="delete"/>
|
||||
|
||||
<action name="公告详情" interceptor="chkZmrLogin" path="/${zhiqim_announcement}/announcementItem.htm" view="/ztmpl/zhiqim_manager/template.htm" include="/zview/zhiqim_announcement/announcementItem.zml" class="org.zhiqim.announcement.action.AnnouncementAction" method="item"/>
|
||||
<action name="公告阅读列表" interceptor="chkZmrLogin" path="/${zhiqim_announcement}/announcementReaderList.htm" view="/ztmpl/zhiqim_manager/inner.htm" include="/zview/zhiqim_announcement/announcementReaderList.zml" class="org.zhiqim.announcement.action.AnnouncementReaderListAction"/>
|
||||
|
||||
<!-- 公告回收站 -->
|
||||
<action name="回收站公告列表" interceptor="chkZmrLogin" path="/${zhiqim_announcement}/announcementRecycle.htm" view="/ztmpl/zhiqim_manager/template.htm" include="/zview/zhiqim_announcement/announcementRecycle.zml" class="org.zhiqim.announcement.action.AnnouncementRecycleAction"/>
|
||||
<action name="删除回收站公告" interceptor="chkZmrLogin" path="/${zhiqim_announcement}/announcementRecycleDelete.htm" redirect="/${zhiqim_announcement}/announcementRecycle.htm" success="删除成功" class="org.zhiqim.announcement.action.AnnouncementRecycleDeleteAction"/>
|
||||
|
||||
</zhiqim-context>
|
||||
@@ -0,0 +1,64 @@
|
||||
<#--左边区域自定义块-->
|
||||
<#function zhiqim_manager_topnav_left_defined()>
|
||||
${zhiqim_announcement_onload()}
|
||||
</#function>
|
||||
|
||||
<#--公告加载-->
|
||||
<#function zhiqim_announcement_onload()>
|
||||
<script>
|
||||
var ws = null;
|
||||
var isClose = true;
|
||||
var num = 0;
|
||||
Z.onload(function()
|
||||
{
|
||||
/*
|
||||
//1.首次登录如果有公告的,要求立即提醒
|
||||
<#if sessionUser.getValue("zoa_announcement_close") != "true" && ZoaAnnouncementDao.hasUnReadAnnouncement(request)>
|
||||
top.Z.alert("有未读的公告,请进入阅读,谢谢!", doClose);
|
||||
</#if>
|
||||
|
||||
//2.建立WS,新公告时提醒
|
||||
if (window.globalWebSocket)
|
||||
ws = globalWebSocket.connect((location.protocol=="https:"?"wss:":"ws:")+"//"+location.hostname+":"+location.port+"/service/ws", "zoa_announcement");
|
||||
else
|
||||
ws = new WebSocket((location.protocol=="https:"?"wss:":"ws:")+"//"+location.hostname+":"+location.port+"/service/ws", "zoa_announcement");
|
||||
ws.onopen = function(){console.log("ws.onopen");isClose=false;};
|
||||
ws.onclose = function(e){console.log("ws.onclose");isClose=true;};
|
||||
ws.onerror = function(e){console.log("ws.onerror");isClose=true;};
|
||||
ws.onmessage = function(e){console.log("ws.onmessage:"+e.data);if (e.data == "zoa_announcement_new"){top.Z.alert("有新的公告发布,请在方便的时候进入阅读,谢谢!");}};
|
||||
|
||||
Z.timer(1000, 10, null, doSend);
|
||||
*/
|
||||
});
|
||||
|
||||
|
||||
function doSend()
|
||||
{
|
||||
if (ws == null || ws.readyState == 2 || ws.readyState == 3)
|
||||
console.log("已关闭");
|
||||
else if (ws.readyState == 0)
|
||||
console.log("未开启");
|
||||
else
|
||||
{
|
||||
console.log("发送");
|
||||
ws.send("一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十");
|
||||
}
|
||||
|
||||
num++;
|
||||
|
||||
// if (num == 5)
|
||||
// ws.close();
|
||||
}
|
||||
|
||||
function doClose()
|
||||
{
|
||||
var ajax = new Z.Ajax();
|
||||
ajax.setClassName("sessionUser");
|
||||
ajax.setMethodName("setValue");
|
||||
ajax.addParam("zoa_announcement_close")
|
||||
ajax.addParam("true");
|
||||
ajax.setSuccess(function(){Z.L.href("${context.getRootPath("/zhiqimAnnouncement/announcement.htm")}", window.mainFrame);});
|
||||
ajax.execute();
|
||||
}
|
||||
</script>
|
||||
</#function>
|
||||
@@ -0,0 +1,57 @@
|
||||
-- ---------------------------------------------------
|
||||
-- 知启蒙大文件上传功能菜单
|
||||
-- ---------------------------------------------------
|
||||
|
||||
|
||||
truncate table ZMR_MENU;
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('ROOT', 'MENU', '系统功能根菜单', '', 0, 0, 0, '', '', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU', 'MENU_010', '系统配置', '系统', 1, 0, 1, 'z-config', '', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010', 'MENU_010_010', '系统基础设置', '', 2, 0, 1, 'z-setting', '/${zhiqim_manager}/menu.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_010', 'MENU_010_010_010', '增加系统菜单', '', 3, 0, 2, '', '/${zhiqim_manager}/menuAdd.htm,/${zhiqim_manager}/menuInsert.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_010', 'MENU_010_010_020', '修改系统菜单', '', 3, 0, 2, '', '/${zhiqim_manager}/menuModify.htm,/${zhiqim_manager}/menuUpdate.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_010', 'MENU_010_010_030', '删除系统菜单', '', 3, 0, 2, '', '/${zhiqim_manager}/menuDelete.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_010', 'MENU_010_010_100', '系统头像管理', '', 3, 0, 2, '', '/${zhiqim_manager}/avatar.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_010', 'MENU_010_010_110', '增加系统头像', '', 3, 0, 2, '', '/${zhiqim_manager}/avatarAdd.htm,/${zhiqim_manager}/avatarInsert.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_010', 'MENU_010_010_120', '修改系统头像', '', 3, 0, 2, '', '/${zhiqim_manager}/avatarModify.htm,/${zhiqim_manager}/avatarUpdate.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_010', 'MENU_010_010_130', '删除系统头像', '', 3, 0, 2, '', '/${zhiqim_manager}/avatarDelete.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_010', 'MENU_010_010_200', '系统配置管理', '', 3, 0, 2, '', '/${zhiqim_manager}/config.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_010', 'MENU_010_010_300', '系统参数设置', '', 3, 0, 2, '', '/${zhiqim_manager}/param.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_010', 'MENU_010_010_310', '首页主题设置', '', 3, 0, 2, '', '/${zhiqim_manager}/themeIndex.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_010', 'MENU_010_010_320', '主页主题设置', '', 3, 0, 2, '', '/${zhiqim_manager}/themeMain.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010', 'MENU_010_050', '部门角色管理', '', 2, 0, 1, 'z-apps', '/${zhiqim_manager}/dept.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_050', 'MENU_010_050_010', '增加部门', '', 3, 0, 2, '', '/${zhiqim_manager}/deptAdd.htm,/${zhiqim_manager}/deptInsert.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_050', 'MENU_010_050_020', '修改部门', '', 3, 0, 2, '', '/${zhiqim_manager}/deptModify.htm,/${zhiqim_manager}/deptUpdate.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_050', 'MENU_010_050_030', '删除部门', '', 3, 0, 2, '', '/${zhiqim_manager}/deptDelete.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_050', 'MENU_010_050_040', '部门成员', '', 3, 0, 2, '', '/${zhiqim_manager}/deptOperator.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_050', 'MENU_010_050_050', '部门权限', '', 3, 0, 2, '', '/${zhiqim_manager}/deptRule.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_050', 'MENU_010_050_100', '角色管理', '', 3, 0, 2, '', '/${zhiqim_manager}/role.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_050', 'MENU_010_050_110', '增加角色', '', 3, 0, 2, '', '/${zhiqim_manager}/roleAdd.htm,/${zhiqim_manager}/roleInsert.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_050', 'MENU_010_050_120', '修改角色', '', 3, 0, 2, '', '/${zhiqim_manager}/roleModify.htm,/${zhiqim_manager}/roleUpdate.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_050', 'MENU_010_050_130', '删除角色', '', 3, 0, 2, '', '/${zhiqim_manager}/roleDelete.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_050', 'MENU_010_050_140', '角色成员', '', 3, 0, 2, '', '/${zhiqim_manager}/roleOperator.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_050', 'MENU_010_050_150', '角色权限', '', 3, 0, 2, '', '/${zhiqim_manager}/roleRule.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010', 'MENU_010_110', '操作员管理', '', 2, 0, 1, 'z-customer', '/${zhiqim_manager}/operator.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_110', 'MENU_010_110_010', '增加操作员', '', 3, 0, 2, '', '/${zhiqim_manager}/operatorAdd.htm,/${zhiqim_manager}/operatorInsert.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_110', 'MENU_010_110_020', '修改操作员', '', 3, 0, 2, '', '/${zhiqim_manager}/operatorModify.htm,/${zhiqim_manager}/operatorUpdate.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_110', 'MENU_010_110_030', '删除操作员', '', 3, 0, 2, '', '/${zhiqim_manager}/operatorDelete.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_110', 'MENU_010_110_040', '查看操作员权限', '', 3, 0, 2, '', '/${zhiqim_manager}/operatorRuleView.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_110', 'MENU_010_110_050', '设置操作员独立权限 ', '', 3, 0, 2, '', '/${zhiqim_manager}/operatorRule.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_110', 'MENU_010_110_060', '设置操作员部门', '', 3, 0, 2, '', '/${zhiqim_manager}/operatorDept.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_110', 'MENU_010_110_070', '设置操作员角色', '', 3, 0, 2, '', '/${zhiqim_manager}/operatorRole.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010', 'MENU_010_150', '操作日志查询', '', 2, 0, 1, 'z-text', '/${zhiqim_manager}/operateLog.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_150', 'MENU_010_150_100', '操作员在线列表', '', 3, 0, 1, '', '/${zhiqim_manager}/operatorOnline.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010', 'MENU_010_220', '文件上传管理', '', 2, 0, 1, 'z-folder', '/zhiqim_upload_large/fileList.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_220', 'MENU_010_210_010', '文件上传', '', 3, 0, 2, '', '/zhiqim_upload_large/fileUpload.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_220', 'MENU_010_210_020', '文件修改', '', 3, 0, 2, '', '/zhiqim_upload_large/fileModify.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_220', 'MENU_010_210_030', '文件删除', '', 3, 0, 2, '', '/zhiqim_upload_large/fileDelete.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_220', 'MENU_010_210_040', '文件碎片查看', '', 3, 0, 2, '', '/zhiqim_upload_large/fileChunkList.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_010_220', 'MENU_010_210_050', '文件碎片删除', '', 3, 0, 2, '', '/zhiqim_upload_large/fileChunkDelete.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU', 'MENU_020', '办公自动化', '办公', 1, 0, 1, 'z-box', '', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_020', 'MENU_020_010', '公告信息管理', '', 2, 0, 1, 'z-setting', '/${zhiqim_announcement}/announcement.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_020_010', 'MENU_020_010_010', '增加删除公告', '', 3, 0, 2, '', '/${zhiqim_announcement}/announcementAdd.htm,/${zhiqim_announcement}/announcementInsert.htm', '');
|
||||
insert into ZMR_MENU (PARENT_CODE, MENU_CODE, MENU_NAME, MENU_NAME_ABBR, MENU_LEVEL, MENU_STATUS, MENU_TYPE, MENU_ICON, MENU_URL, MENU_DESC) values ('MENU_020_010', 'MENU_020_010_020', '删除回收站公告', '', 3, 0, 2, '', '/${zhiqim_announcement}/announcementRecyleDelete.htm', '');
|
||||
commit;
|
||||
|
||||
-- ---------------------------------------------------
|
||||
-- 知启蒙大文件上传功能菜单创建完成
|
||||
-- ---------------------------------------------------
|
||||
@@ -0,0 +1 @@
|
||||
hi.abc,哈哈
|
||||
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>${context.getContextName()}</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
||||
<meta name="Author" content="${context.getContextName()}" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
index.htm
|
||||
<br><br>
|
||||
<a href="ws.htm">ws.htm</a>
|
||||
|
||||
<a href="jdk-7u80-windows-x64.exe">下载</a>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
hi.jsp
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>${context.getContextName()}</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
||||
<meta name="Author" content="${context.getContextName()}" />
|
||||
<script>
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
hi,ftm,我来了
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,39 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>${context.getContextName()}</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
||||
<meta name="Author" content="${context.getContextName()}" />
|
||||
${Scripts.src("/zinc/zhiqim_v1.4.0.r2018010101.min.js")}
|
||||
<script>
|
||||
var ws = null;
|
||||
Z.onload(function()
|
||||
{
|
||||
ws = new WebSocket("ws://"+location.hostname+":"+location.port+"/service/ws", "zoa_announcement");
|
||||
ws.onopen = function(){console.log("ws.onopen");};
|
||||
ws.onclose = function(e){console.log("ws.onclose");};
|
||||
ws.onerror = function(e){console.log("ws.onerror");};
|
||||
ws.onmessage = function(e){console.log("ws.onmessage:"+e.data);if (e.data == "zoa_announcement_new"){top.Z.alert("有新的公告发布,请在方便的时候进入阅读,谢谢!");}};
|
||||
|
||||
Z.timer(1000, 100, null, send);
|
||||
});
|
||||
|
||||
function send()
|
||||
{
|
||||
console.log("中文");
|
||||
ws.send("一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
index.htm
|
||||
<br><br>
|
||||
<a href="abc.htm">abc.htm</a>
|
||||
|
||||
<a href="jdk-7u80-windows-x64.exe">下载</a>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,63 @@
|
||||
<script>
|
||||
function doDialog(announcementId)
|
||||
{
|
||||
var dialog = new Z.Dialog();
|
||||
dialog.title = "已阅读人员列表";
|
||||
dialog.url = "announcementReaderList.htm?announcementId="+announcementId;
|
||||
dialog.width = 392;
|
||||
dialog.height = 423;
|
||||
dialog.execute();
|
||||
}
|
||||
</script>
|
||||
|
||||
${zhiqim_manager_breadcrumb("公告信息")}
|
||||
${zhiqim_manager_content()}
|
||||
|
||||
<#-- 导航 -->
|
||||
<div class="z-tabnav-main z-mg-b20 ${zmr_color_class}">
|
||||
<nav>
|
||||
<ul>
|
||||
<li class="z-active">公告信息</li>
|
||||
<li onclick="Z.L.href('announcementRecycle.htm');">公告回收站</li>
|
||||
</ul>
|
||||
<div class="z-float-left z-mg10">
|
||||
<form name="theForm" method="post">
|
||||
<input name="announcementTitle" class="z-float-left z-input z-w300 zi-bd-r-none" value="${announcementTitle}" maxlength="64" placeholder="模糊匹配公告标题">
|
||||
<button class="z-float-left z-button z-w80 zi-bd-rd0 ${zmr_color_class}"><i class="z-font z-query"></i>查询</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="z-text-right z-mg-t10 z-mg-r5">
|
||||
<#if ZmrPathRule.check(request, "/"+zhiqim_announcement+"/announcementAdd.htm")>
|
||||
<button class="z-button ${zmr_color_class}" onclick="Z.L.href('announcementAdd.htm');"><i class="z-ico z-add"></i>增加办公公告</button>
|
||||
</#if>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<#-- 列表 -->
|
||||
<table class="z-table z-bordered z-pd10 z-bg-white z-text-center">
|
||||
<tr class="zi-h40" bgcolor="${zmr_thead_bgcolor}">
|
||||
<td width="110">公告类型</td>
|
||||
<td width="*">公告标题</td>
|
||||
<td width="110">发布人</td>
|
||||
<td width="160">发布时间</td>
|
||||
<td width="90">已读/未读</td>
|
||||
<td width="180">操作</td>
|
||||
</tr>
|
||||
${zhiqim_manager_tr_no_record(result, 6, "没有公告信息")}
|
||||
<#for item : result.list()>
|
||||
<tr class="z-pointer z-h50" ${zhiqim_manager_tr_onmouse()} ${zhiqim_manager_tr_click_radio()}>
|
||||
<td><#if item.getAnnouncementType()==1>行政公告</#if><#if item.getAnnouncementType()==2>假日公告</#if><#if item.getAnnouncementType()==3>会议公告</#if></td>
|
||||
<td><a href="announcementItem.htm?announcementId=${item.getAnnouncementId()}">${item.getAnnouncementTitle()}</a></td>
|
||||
<td>${item.getAnnouncementPublisher()}</td>
|
||||
<td>${Sqls.toDateTimeString(item.getAnnouncementTime())}</td>
|
||||
<td><#if item.getOperatorCode() == null><span class="z-text-cyan">未读</span><#else>已读</#if></td>
|
||||
<td>
|
||||
<button class="z-button z-w100 z-h30 z-mg-r10 ${zmr_color_class}" onclick="doDialog('${item.getAnnouncementId()}')">查看阅读列表</button>
|
||||
<button class="z-button z-xsmall z-h30 z-font z-delete zi-px14 z-red" title="删除" onclick="Z.L.confirm('announcementDelete.htm?announcementId=${item.getAnnouncementId()}', '是否删除该公告?', null, zCallFrame);"></button>
|
||||
</td>
|
||||
</tr>
|
||||
</#for>
|
||||
</table>
|
||||
${zhiqim_manager_paging (result)}
|
||||
${zhiqim_manager_content_end()}
|
||||
@@ -0,0 +1,39 @@
|
||||
<#def designatedPath="/"+zhiqim_announcement+"/announcement.htm"/>
|
||||
${request.getValidateScript()}
|
||||
${zhiqim_manager_history("announcement.htm")}
|
||||
${Scripts.onload("document.theForm.announcementTitle.focus();")}
|
||||
|
||||
${zhiqim_manager_breadcrumb_parent("announcement.htm", "公告信息", "增加公告")}
|
||||
${zhiqim_manager_content()}
|
||||
<form name="theForm" action="announcementInsert.htm" method="post" onsubmit="return validateForm(this);" data-role="z-call-frame">
|
||||
<table class="z-table z-bordered z-h50-tr z-pd10 z-bg-white z-lh150p">
|
||||
<tr class="zi-h40 z-bg-gray z-bold">
|
||||
<td colspan="2">增加公告</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="40%">公告标题:<span class="z-color-999">(公告标题不能为空,[1, 64]范围)</span></td>
|
||||
<td width="*"><input name="announcementTitle" class="z-input z-w300 ${zmr_color_class}" maxlength="64" spellcheck="false"><span class="z-color-red"> *</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>公告类型:<span class="z-color-999">(请选择)</span></td>
|
||||
<td>
|
||||
<select name="announcementType" class="z-select z-w300 ${zmr_color_class}" data-role="z-select" data-class="${styleColor}">
|
||||
<option value="1">行政公告</option>
|
||||
<option value="2">假日公告</option>
|
||||
<option value="3">会议公告</option>
|
||||
</select>
|
||||
<span class="z-color-red"> *</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="zi-pd-l10 zi-pd15" colspan="2">
|
||||
<div class="z-mg-t20">公告内容:<span class="z-color-999">(不能为空,但最长不能超过1024个字符)</span><span class="z-color-red"> *</span></div>
|
||||
<div class="z-pd-t20 z-pd-b20">
|
||||
<textarea name="announcementContent" class="z-textarea z-w100p ${zmr_color_class}" rows="15" size="30" maxlength="1024"></textarea>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
${zhiqim_manager_submit()}
|
||||
</form>
|
||||
${zhiqim_manager_content_end()}
|
||||
@@ -0,0 +1,35 @@
|
||||
<#def designatedPath="/"+zhiqim_announcement+"/announcement.htm"/>
|
||||
${zhiqim_manager_history("announcement.htm")}
|
||||
|
||||
${zhiqim_manager_breadcrumb_parent("announcement.htm", "公告信息", "公告详情")}
|
||||
${zhiqim_manager_content()}
|
||||
<#-- 办公公告详情 --->
|
||||
<table class="z-table z-bordered z-h40-tr z-pd10 z-bg-white z-lh150p">
|
||||
<tr>
|
||||
<td colspan="6" class="z-bg-gray">公告详情</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>公告标题:</td>
|
||||
<td colspan="3">${item.getAnnouncementTitle()}</td>
|
||||
<td>公告类型:</td>
|
||||
<td><#if item.getAnnouncementType()==1>行政公告</#if><#if item.getAnnouncementType()==2>假日公告</#if><#if item.getAnnouncementType()==3>会议公告</#if></td>
|
||||
<tr>
|
||||
<td>发布时间:</td>
|
||||
<td>${Sqls.toDateTimeString(item.getAnnouncementTime())}</td>
|
||||
<td>发布者:</td>
|
||||
<td>${item.getAnnouncementPublisher()}</td>
|
||||
<td>公告状态:</td>
|
||||
<td><#if item.getAnnouncementStatus()==0>正常</#if><#if item.getAnnouncementStatus()==1><span class="z-color-red">已删除</span></#if></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="6" class="z-bg-gray">公告详情内容</td>
|
||||
</tr>
|
||||
<tr class="zi-h100">
|
||||
<td class="z-text-top">公告正文</td>
|
||||
<td colspan="5" class="z-text-top z-text-prewrap">#{item.getAnnouncementContent()}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="6"><a href="announcement.htm">返回上一页</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
${zhiqim_manager_content_end()}
|
||||
@@ -0,0 +1,39 @@
|
||||
${Styles.htmlOverflowHidden()}
|
||||
<script>
|
||||
Z.onload(function()
|
||||
{
|
||||
Z(document.forms[0].operatorKey).focusEnd();
|
||||
});
|
||||
</script>
|
||||
|
||||
<#-- 查询 -->
|
||||
<div class="z-fixed z-t0 z-l0 z-w100p z-pd10 z-bg-gray">
|
||||
<form method="post">
|
||||
<input name="operatorKey" class="z-float-left z-input z-w300 zi-h35 zi-bd-r-none" placeholder="操作员编码或名称" value="${operatorKey}" maxlength="20">
|
||||
<button type="submit" class="z-float-left z-button z-w70 z-h35 zi-bd-rd0 ${zmr_color_class}"><i class="z-font z-query"></i></button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<#-- 列表 -->
|
||||
<div class="z-w100p z-pd10 z-overflow-auto" style="margin-top:55px;height:306px;">
|
||||
<table class="z-table z-bordered z-pd5 z-text-center">
|
||||
<tr class="z-h40 z-bg-gray">
|
||||
<td width="90">操作员头像</td>
|
||||
<td width="110">操作员编码</td>
|
||||
<td width="*">操作员姓名</td>
|
||||
</tr>
|
||||
${zhiqim_manager_tr_no_record(result, 3, "没有阅读人员信息")}
|
||||
<#for item : result.list()>
|
||||
<tr class="z-pointer" ${zhiqim_manager_tr_onmouse()} ${zhiqim_manager_tr_click_checkbox()}>
|
||||
<td><img src="${sessionUser.getAvatarUrl(item.getOperatorAvatar(), 50)}" class="z-w50 z-h50 z-bd-rd50p"></td>
|
||||
<td>${item.getOperatorCode()}</td>
|
||||
<td>${item.getOperatorName()}</td>
|
||||
</tr>
|
||||
</#for>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<#-- 操作 -->
|
||||
<div class="z-fixed z-b0 z-l0 z-w100p z-h60 z-pd10 z-bg-gray z-text-center">
|
||||
<button class="z-button z-large z-w150 z-mg-l10 ${zmr_color_class}" onclick="parent.Z.Dialog.close(location.hash);">关闭</button>
|
||||
</div>
|
||||
@@ -0,0 +1,42 @@
|
||||
<#def designatedPath="/"+zhiqim_announcement+"/announcement.htm"/>
|
||||
${zhiqim_manager_breadcrumb("公告回收站")}
|
||||
${zhiqim_manager_content()}
|
||||
|
||||
<#-- 导航 -->
|
||||
<div class="z-tabnav-main z-mg-b20 ${zmr_color_class}">
|
||||
<nav>
|
||||
<ul>
|
||||
<li onclick="Z.L.href('announcement.htm');">公告信息</li>
|
||||
<li class="z-active">公告回收站</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<#-- 列表 -->
|
||||
<table class="z-table z-bordered z-pd10 z-bg-white z-text-center">
|
||||
<tr class="z-h40" bgcolor="${zmr_thead_bgcolor}">
|
||||
<td width="110">公告类型</td>
|
||||
<td width="*">公告标题</td>
|
||||
<td width="100">发布人</td>
|
||||
<td width="160">发布时间</td>
|
||||
<td width="100">操作</td>
|
||||
</tr>
|
||||
${zhiqim_manager_tr_no_record(result, 6, "没有公告信息")}
|
||||
<#for item : result.list()>
|
||||
<tr class="z-pointer z-h50" ${zhiqim_manager_tr_onmouse()} ${zhiqim_manager_tr_click_radio()}>
|
||||
<td><#if item.getAnnouncementType()==1>行政公告</#if><#if item.getAnnouncementType()==2>假日公告</#if><#if item.getAnnouncementType()==3>会议公告</#if></td>
|
||||
<td><a href="announcementItem.htm?announcementId=${item.getAnnouncementId()}">${item.getAnnouncementTitle()}</a></td>
|
||||
<td>${item.getAnnouncementPublisher()}</td>
|
||||
<td>${Sqls.toDateTimeString(item.getAnnouncementTime())}</td>
|
||||
<td>
|
||||
<#if ZmrAdminRule.check(request)>
|
||||
<button class="z-button z-xsmall z-h25 z-font z-delete zi-px14 z-red" title="删除" onclick="Z.L.confirm('announcementRecycleDelete.htm?announcementId=${item.getAnnouncementId()}', '是否彻底删除该公告?', null, zCallFrame);"></button>
|
||||
<#else>
|
||||
--
|
||||
</#if>
|
||||
</td>
|
||||
</tr>
|
||||
</#for>
|
||||
</table>
|
||||
${zhiqim_manager_paging(result)}
|
||||
${zhiqim_manager_content_end()}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
/**
|
||||
* HTTP证书对象
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2016-7-13 新建与整理
|
||||
*/
|
||||
public class HttpCertificate
|
||||
{
|
||||
private final String _sslSessionId;
|
||||
private final X509Certificate[] _certs;
|
||||
|
||||
public HttpCertificate(String sslSessionId, X509Certificate[] certs)
|
||||
{
|
||||
this._sslSessionId = sslSessionId;
|
||||
this._certs = certs;
|
||||
}
|
||||
|
||||
public String getSessionId()
|
||||
{
|
||||
return _sslSessionId;
|
||||
}
|
||||
|
||||
public X509Certificate[] getCerts()
|
||||
{
|
||||
return _certs;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* HTTP AIO/BIO连接通道接口
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2018-11-16 新建与整理
|
||||
*/
|
||||
public interface HttpChannel
|
||||
{
|
||||
/**
|
||||
* 从连接通道中获取缓冲
|
||||
*
|
||||
* @param buf 缓冲
|
||||
* @return 读取到的数目
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
public int read(ByteBuffer buf) throws IOException;
|
||||
|
||||
/**
|
||||
* 写入缓冲到连接通道中
|
||||
*
|
||||
* @param buf 缓冲
|
||||
* @return 写入到的数目
|
||||
* @throws Exception 异常
|
||||
*/
|
||||
public int write(ByteBuffer buf) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.zhiqim.kernel.logging.Log;
|
||||
import org.zhiqim.kernel.logging.LogFactory;
|
||||
import org.zhiqim.kernel.util.seqs.Sequence;
|
||||
|
||||
/**
|
||||
* HTTP连接接口定义
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2016-7-18 新建与整理
|
||||
*/
|
||||
public interface HttpConnection extends HttpdConstants
|
||||
{
|
||||
public Log log = LogFactory.getLog(HttpConnection.class);
|
||||
public Sequence sequence = new Sequence(6);
|
||||
|
||||
/********************************************************************/
|
||||
//连接中状态
|
||||
/********************************************************************/
|
||||
|
||||
/** 是否活动 */
|
||||
public boolean isActive();
|
||||
|
||||
/** 是否超时 */
|
||||
public boolean isOvertime();
|
||||
|
||||
/** 是否已关闭 */
|
||||
public boolean isClosed();
|
||||
|
||||
/********************************************************************/
|
||||
//连接中的websocket
|
||||
/********************************************************************/
|
||||
|
||||
/** 是否是websocket连接 */
|
||||
public boolean isWebsocket();
|
||||
|
||||
/** 升级为Websocket连接 */
|
||||
public void doWebsocket(HttpContext context, String protocol, String sessionId);
|
||||
|
||||
/********************************************************************/
|
||||
//连接中write&close
|
||||
/********************************************************************/
|
||||
|
||||
/** 写入数据 */
|
||||
public void write(byte[] data) throws IOException;
|
||||
|
||||
/** 写入数据 */
|
||||
public void write(byte[] data, int off, int len) throws IOException;
|
||||
|
||||
/** 关闭连接 */
|
||||
public void close();
|
||||
|
||||
/********************************************************************/
|
||||
//连接中的相关连的 id & listener
|
||||
/********************************************************************/
|
||||
|
||||
/** 连接编号 */
|
||||
public String getId();
|
||||
|
||||
/** 连接对应的监听器 */
|
||||
public HttpListener getListener();
|
||||
|
||||
/** 获取远程地址 */
|
||||
public String getRemoteAddr();
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.zhiqim.kernel.config.Group;
|
||||
import org.zhiqim.kernel.control.Configurable;
|
||||
import org.zhiqim.kernel.extend.HashMapSO;
|
||||
import org.zhiqim.kernel.extend.HashSetS;
|
||||
|
||||
/**
|
||||
* HTTP上下文环境接口定义
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2016-7-15 新建与整理
|
||||
*/
|
||||
public interface HttpContext extends Configurable
|
||||
{
|
||||
/*********************************************************************/
|
||||
//创建 & 销毁
|
||||
/*********************************************************************/
|
||||
|
||||
/** 上下文环境编号 */
|
||||
public String getId();
|
||||
|
||||
/** 是否运行中 */
|
||||
public boolean isRunning();
|
||||
|
||||
/** 资源是否在类路径中 */
|
||||
public boolean isClasspath();
|
||||
|
||||
/** 创建 */
|
||||
public boolean create(Group group)throws Exception;
|
||||
|
||||
/** 销毁 */
|
||||
public void destroy()throws Exception;
|
||||
|
||||
/** 设置服务 */
|
||||
public void setServer(HttpServer server);
|
||||
|
||||
/** 获取服务 */
|
||||
public HttpServer getServer();
|
||||
|
||||
/** 获取上行最大内容长度 */
|
||||
public int getMaxContentLength();
|
||||
|
||||
/** 获取设置的分块大小 */
|
||||
public int getChunkSize();
|
||||
|
||||
/** 获取静态文件有效期 */
|
||||
public int getExpires();
|
||||
|
||||
/** 判断是否是过滤的地址 */
|
||||
public boolean isFilterPath(String pathInContext);
|
||||
|
||||
/** 获取匹配的处理器 */
|
||||
public HttpHandler getMatchHandler(String pathInContext);
|
||||
|
||||
/**
|
||||
* 公共处理文件资源,该方法可以在匹配到的Handler中发现子匹配失败时回跳到文件资源处理中再检查一次
|
||||
*
|
||||
* @param request 请求
|
||||
* @param response 响应
|
||||
* @exception HttpException HTTP异常
|
||||
* @exception IOException IO异常
|
||||
*/
|
||||
public void handleResource(HttpHeader header, HttpSender sender)throws HttpException, IOException;
|
||||
|
||||
/**
|
||||
* 默认处理请求,子类可以重写,默认查询Handler,如果查到对应由Handler处理,否则认为由ResourceHandler处理
|
||||
*
|
||||
* @param request 请求
|
||||
* @param response 响应
|
||||
* @exception HttpException HTTP异常
|
||||
* @exception IOException IO异常
|
||||
*/
|
||||
public void handle(HttpRequest request, HttpResponse response)throws HttpException, IOException;
|
||||
|
||||
/*********************************************************************/
|
||||
//上下文环境基本属性相关方法
|
||||
/*********************************************************************/
|
||||
|
||||
/** 判断是否有上下文环境域名 */
|
||||
public HashSetS getContextDomains();
|
||||
|
||||
/** 获取上下文环境路径 */
|
||||
public String getContextPath();
|
||||
|
||||
/** 获取缺省编码 */
|
||||
public String getDefaultEncoding();
|
||||
|
||||
/** 获取上下文环境资源路径 */
|
||||
public String getResourcePath();
|
||||
|
||||
/** 获取上下文环境对应的真实路径 */
|
||||
public String getRealPath(String path);
|
||||
|
||||
/** 获取上下文环境下绝对路径转为根环境下的绝对路径,如contextPath=/doc,path=/index.htm,得到/doc/index.htm */
|
||||
public String getRootPath(String path);
|
||||
|
||||
/** 获取上下文环境欢迎页 */
|
||||
public String getWelcomeUrl();
|
||||
|
||||
/** 获取上下文环境404页跳转页 */
|
||||
public String getNotFoundUrl();
|
||||
|
||||
/** 获取上下文环境404页处理器 */
|
||||
public HttpEntity getNotFoundHandler();
|
||||
|
||||
/** 获取上下文环境会话管理器 */
|
||||
public HttpSessionManager getSessionManager();
|
||||
|
||||
/** 设置指定的会话失效 */
|
||||
public void invalidateSession(String sessionId);
|
||||
|
||||
/** 是否使用Cookie */
|
||||
public boolean isCookieUse();
|
||||
|
||||
/** 获取使用Cookie时保存的域名 */
|
||||
public String getCookieDomain();
|
||||
|
||||
/** 获取使用Cookie时保存的路径 */
|
||||
public String getCookiePath();
|
||||
|
||||
/** 获取使用Cookie时保存的端口 */
|
||||
public int getCookiePort();
|
||||
|
||||
/**
|
||||
* 获取该资源内的资源字符串
|
||||
*
|
||||
* @param path 请求
|
||||
* @return =null表示不在该资源内,!=null表示在该资源内并读取到内容
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public String getResourceString(String path) throws IOException;
|
||||
|
||||
/**
|
||||
* 获取该资源内的资源字符串
|
||||
*
|
||||
* @param path 请求
|
||||
* @param encoding 编码
|
||||
* @return =null表示不在该资源内,!=null表示在该资源内并读取到内容
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public String getResourceString(String path, String encoding) throws IOException;
|
||||
|
||||
/**
|
||||
* 读取资源目录下的文件名和目录名,目录名以/结尾,用于显示目录下列表
|
||||
*
|
||||
* @param folderPath 目录地址
|
||||
* @return 名称列表
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public List<String> getResourceNameList(String folderPath) throws IOException;
|
||||
|
||||
/*********************************************************************/
|
||||
//上下文环境自定义属性相关方法
|
||||
/*********************************************************************/
|
||||
|
||||
/** 设置属性 */
|
||||
public void setAttribute(String key, Object value);
|
||||
|
||||
/** 设置属性(通过类结构) */
|
||||
public <T> void setAttribute(Class<T> key, T value);
|
||||
|
||||
/** 是否有该属性 */
|
||||
public boolean hasAttribute(String key);
|
||||
|
||||
/** 获取属性表 */
|
||||
public HashMapSO getAttributes();
|
||||
|
||||
/** 获取属性 */
|
||||
public Object getAttribute(String key);
|
||||
|
||||
/** 获取上属性(通过类结构) */
|
||||
public <T> T getAttribute(Class<T> key);
|
||||
|
||||
/** 获取属性,如果属性不存在则使用缺省值 */
|
||||
public Object getAttribute(String key, Object defaultValue);
|
||||
|
||||
/** 获取上下文环境名称 */
|
||||
public String getContextName();
|
||||
|
||||
/** 获取上下文环境版本 */
|
||||
public String getContextVersion();
|
||||
|
||||
/** 获取字符串 */
|
||||
public String getAttributeString(String key);
|
||||
|
||||
/** 获取字符串 ,如果属性不存在则使用缺省值*/
|
||||
public String getAttributeString(String key, String defaultValue);
|
||||
|
||||
/** 获取整型 */
|
||||
public int getAttributeInt(String key);
|
||||
|
||||
/** 获取整型 ,如果属性不存在则使用缺省值 */
|
||||
public int getAttributeInt(String key, int defaultValue);
|
||||
|
||||
/** 获取长整型 */
|
||||
public long getAttributeLong(String key);
|
||||
|
||||
/** 获取长整型 ,如果属性不存在则使用缺省值 */
|
||||
public long getAttributeLong(String key, long defaultValue);
|
||||
|
||||
/** 获取布尔型 ,如果属性不存在则使用缺省值 */
|
||||
public boolean getAttributeBoolean(String key, boolean defaultValue);
|
||||
|
||||
/*********************************************************************/
|
||||
//上下文环境Websocket相关方法
|
||||
/*********************************************************************/
|
||||
|
||||
/** 获取Websocket管理器 */
|
||||
public HttpWebsocketManager getWebsocketManager();
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
/**
|
||||
* HTTP 上下文环境的ClassLoader
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public class HttpContextLoader extends URLClassLoader
|
||||
{
|
||||
private static final String[] _SYSTEM_CLASSES_ = new String [] {"java.","javax.xml.","org.xml.","org.w3c.","org.zhiqim."};
|
||||
|
||||
private ClassLoader _parent;
|
||||
|
||||
public HttpContextLoader(ClassLoader parent)
|
||||
{
|
||||
super(new URL[0], parent);
|
||||
this._parent = parent;
|
||||
}
|
||||
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException
|
||||
{
|
||||
return loadClass(name, false);
|
||||
}
|
||||
|
||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
|
||||
{
|
||||
Class<?> c = findLoadedClass(name);
|
||||
if (c != null)
|
||||
return c;
|
||||
|
||||
ClassNotFoundException ex= null;
|
||||
try{c = this.findClass(name);}catch (ClassNotFoundException e){ex = e;}
|
||||
|
||||
if (c == null && _parent != null)
|
||||
try{c = _parent.loadClass(name);}catch (ClassNotFoundException e){ex = e;}
|
||||
|
||||
if (c == null)
|
||||
throw ex;
|
||||
|
||||
if (resolve)
|
||||
resolveClass(c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
public URL getResource(String name)
|
||||
{
|
||||
URL url = null;
|
||||
boolean triedParent = false;
|
||||
if (isSystemPath(name))
|
||||
{
|
||||
triedParent = true;
|
||||
url = _parent.getResource(name);
|
||||
}
|
||||
|
||||
if (url == null)
|
||||
{
|
||||
url = this.findResource(name);
|
||||
if (url == null && name.startsWith("/"))
|
||||
url = this.findResource(name.substring(1));
|
||||
}
|
||||
|
||||
if (url == null && !triedParent)
|
||||
url = _parent.getResource(name);
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/** 是否指定为系统路径 */
|
||||
public boolean isSystemPath(String name)
|
||||
{
|
||||
name = name.replace('/','.');
|
||||
while(name.startsWith("."))
|
||||
name = name.substring(1);
|
||||
|
||||
for (String c : _SYSTEM_CLASSES_)
|
||||
{
|
||||
if (c.endsWith("."))
|
||||
{//类前缀
|
||||
if (name.startsWith(c))
|
||||
return true;
|
||||
}
|
||||
else if (name.equals(c))
|
||||
{//类全称
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import org.zhiqim.kernel.util.Strings;
|
||||
import org.zhiqim.kernel.util.Urls;
|
||||
|
||||
/**
|
||||
* HTTP Cookie类
|
||||
* 1.name Cookie名称
|
||||
* 2.value Cookie值
|
||||
* 3.Version Cookie遵循的版本
|
||||
* 4.Max-Age Cookie有效期,为0表示不设置关闭浏览器即失效,单位:秒,替换Expires字段,告之浏览器保留时间,而不是到期时间
|
||||
* 5.Discard Cookie有效期,是否在会话结束后丢弃该 Cookie 项,默认为 fasle
|
||||
* 6.Domain Cookie指定的域,如果有域建议添加
|
||||
* 7.Port Cookie指定的端口列表,多个逗号隔开,我们这里只支持一个,Version=1时引入,不过多大还不支持该属性
|
||||
* 8.Path Cookie的虚拟目录,取值为contextPath,由HttpServer决定,不需要传入
|
||||
* 9.Secure Cookie安全SSL时才传送
|
||||
* 10.HttpOnly Cookie仅HTTP使用,由IE引入,大多都支持,强制填写
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public class HttpCookie implements HttpdConstants
|
||||
{
|
||||
private String name;
|
||||
private String value;
|
||||
private int maxAge;
|
||||
private boolean secure;
|
||||
|
||||
public HttpCookie(String name, String value)
|
||||
{
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public HttpCookie(String name, String value, int maxAge)
|
||||
{
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.maxAge = maxAge;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
public int getMaxAge()
|
||||
{
|
||||
return maxAge;
|
||||
}
|
||||
|
||||
public void setMaxAge(int maxAge)
|
||||
{
|
||||
this.maxAge = maxAge;
|
||||
}
|
||||
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setValue(String value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void setSecure(boolean secure)
|
||||
{
|
||||
this.secure = secure;
|
||||
}
|
||||
|
||||
public boolean isSecure()
|
||||
{
|
||||
return secure;
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
//以下为自定义方法
|
||||
/**************************************************************/
|
||||
|
||||
/**
|
||||
* 响应Cookie,支持PATH,DOMAIN和PORT
|
||||
*
|
||||
* @param contextPath 上下文路径
|
||||
* @param domain 域名
|
||||
* @param port 端口
|
||||
* @return Cookie响应
|
||||
*/
|
||||
public String getResponse(String contextPath, String domain, int port)
|
||||
{
|
||||
return new StringBuilder(_SET_COOKIE_).append(_COLON_).append(getResponseValue(contextPath, domain, port)).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应Cookie,支持PATH,DOMAIN和PORT
|
||||
*
|
||||
* @param contextPath 上下文路径
|
||||
* @param domain 域名
|
||||
* @param port 端口
|
||||
* @return Cookie响应
|
||||
*/
|
||||
public String getResponseValue(String contextPath, String domain, int port)
|
||||
{
|
||||
StringBuilder strb = new StringBuilder();
|
||||
//强制规定采用UTF8进行URL编码,读取时解码,保证统一,防止更换编码时读取异常
|
||||
strb.append(name).append("=").append(Urls.encodeUTF8(value));
|
||||
strb.append(";").append(_COOKIE_VERSION_).append("=").append(1);
|
||||
|
||||
//默认不设置有效期即浏览器关闭即失效,如果有设置要求,则加入
|
||||
if (maxAge == 0)
|
||||
strb.append(";").append(_COOKIE_DISCARD_).append("=").append("\"true\"");
|
||||
else
|
||||
strb.append(";").append(_COOKIE_MAX_AGE_).append("=").append(maxAge);
|
||||
|
||||
//强制加上域和端口
|
||||
if (domain != null)
|
||||
strb.append(";").append(_COOKIE_DOMAIN_).append("=").append(domain);
|
||||
|
||||
if (port != -1)
|
||||
strb.append(";").append(_COOKIE_PORT_).append("=").append(port);
|
||||
|
||||
//强制加上路径
|
||||
strb.append(";").append(_COOKIE_PATH_).append("=").append(Strings.addEndsWith(contextPath, "/"));
|
||||
|
||||
//默认不增加SSL时才传递
|
||||
if (secure)
|
||||
strb.append(";").append(_COOKIE_SECURE_);
|
||||
|
||||
//强制加上仅HTTP操作
|
||||
strb.append(";").append(_COOKIE_HTTP_ONLY);
|
||||
return strb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 对应HTTP一个处理的实体,和HttpHandler不同的是:
|
||||
* 1.只需消息头内容
|
||||
* 2.对应实际的一个文件或处理,无其他业务逻辑
|
||||
* 3.处理完成后即发送
|
||||
*
|
||||
* 用于静态文件等,无需创建复杂的HttpRequest和HttpResponse
|
||||
*
|
||||
* @see HttpExecutor 业务处理器
|
||||
* @version v1.0.0 @author zouzhigang 2016-7-19 新建与整理
|
||||
*/
|
||||
public interface HttpEntity extends HttpHandler
|
||||
{
|
||||
/**
|
||||
* 处理HTTP请求, 来自GET,POST方法
|
||||
*
|
||||
* @param header 请求头
|
||||
* @param sender 响应发送者
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public void handle(HttpHeader header, HttpSender sender) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.zhiqim.httpd.constants.HttpStatus;
|
||||
|
||||
|
||||
/**
|
||||
* 定义HTTP级错误,捕捉时直接返回错误信息
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public class HttpException extends IOException
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int code;
|
||||
|
||||
public int getCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
|
||||
public HttpException()
|
||||
{
|
||||
code = HttpdConstants._400_BAD_REQUEST_;
|
||||
}
|
||||
|
||||
public HttpException(String message)
|
||||
{
|
||||
super(message);
|
||||
code = HttpdConstants._503_SERVER_UNAVAILABLE_;
|
||||
}
|
||||
|
||||
public HttpException(int code)
|
||||
{
|
||||
this.code=code;
|
||||
}
|
||||
|
||||
public HttpException(int code, String message)
|
||||
{
|
||||
super(message);
|
||||
this.code=code;
|
||||
}
|
||||
|
||||
public String getReason()
|
||||
{
|
||||
return HttpStatus.getStatusMsg(code);
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
String message = getMessage();
|
||||
String reason = getReason();
|
||||
return "HttpException("+code+","+reason+","+message+")";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 定义HTTP业务处理器,和HttpEntity不同的是:
|
||||
* 1.创建完善的HttpRequest和HttpResponse用于业务处理
|
||||
* 2.支持HttpSession和Validate等业务形态
|
||||
* 3.支持view,redirect,forward等业务形态
|
||||
*
|
||||
* @see HttpEntity 实体处理器
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public interface HttpExecutor extends HttpHandler
|
||||
{
|
||||
/**
|
||||
* 处理HTTP请求, 来自GET,POST方法
|
||||
*
|
||||
* @param request 请求
|
||||
* @param response 响应
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
public void handle(HttpRequest request, HttpResponse response) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
|
||||
/**
|
||||
* 定义HTTP业务处理器,和两种处理器
|
||||
* @see HttpEntity 实体处理器,用于资源静态文件和错误处理等,没有session/cookie也不需要解析内容
|
||||
* @see HttpExecutor 逻辑处理器,用于业务处理,初始化数据比较多,要求解析内容和session/cookie/parameter/validate等
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public interface HttpHandler extends HttpdConstants
|
||||
{
|
||||
public boolean isMatch(String pathInContext);
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import org.zhiqim.kernel.control.Configurable;
|
||||
import org.zhiqim.kernel.extend.HashMapSS;
|
||||
import org.zhiqim.kernel.logging.Log;
|
||||
|
||||
public interface HttpHeader extends HttpdConstants, Configurable
|
||||
{
|
||||
/** 获取日志对象 */
|
||||
public Log getLog();
|
||||
|
||||
/** 获取对应的HTTP监听器监听端口 */
|
||||
public int getListenerPort();
|
||||
|
||||
/** 获取发送器 */
|
||||
public HttpSender getSender();
|
||||
|
||||
/** 获取客户端IP地址 */
|
||||
public String getRemoteAddr();
|
||||
|
||||
/** 获取请求正在处理的上下文环境 */
|
||||
public HttpContext getContext();
|
||||
|
||||
/** 获取在上下文环境下的路径 */
|
||||
public String getPathInContext();
|
||||
|
||||
/** 获取资源文件下绝对路径 */
|
||||
public String getPathOnResource();
|
||||
|
||||
/***********************************************************************/
|
||||
//获取和判断请求行信息,包括协议、方法、版本、URI等
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取请求行 */
|
||||
public String getHeaderLine();
|
||||
|
||||
/** 获取请求版本 */
|
||||
public String getVersion();
|
||||
|
||||
/** 获取URI路径,以/开头,如/test.html,如果没有文件后缀则为'/' */
|
||||
public String getPath();
|
||||
|
||||
/** 获取请求方法 */
|
||||
public String getMethod();
|
||||
|
||||
/** 是否是HEAD方法 */
|
||||
public boolean isMethodHead();
|
||||
|
||||
/** 是否是GET方法 */
|
||||
public boolean isMethodGet();
|
||||
|
||||
/** 是否是POST方法 */
|
||||
public boolean isMethodPost();
|
||||
|
||||
/** 是否需要响应内容 */
|
||||
public boolean isMethodResponseContent();
|
||||
|
||||
/** 是否WebSocket */
|
||||
public boolean isWebSocket();
|
||||
|
||||
/** 获取查询串 */
|
||||
public String getQueryString();
|
||||
|
||||
/** 获取HOST:PORT */
|
||||
public String getHostPort();
|
||||
|
||||
/** 如果有PORT只仅HOST */
|
||||
public String getHostOnly();
|
||||
|
||||
/** 获取浏览器代理 */
|
||||
public String getUserAgent();
|
||||
|
||||
/** 获取URI虚拟目录信息 */
|
||||
public String getVirtualDirectory();
|
||||
|
||||
/***********************************************************************/
|
||||
//获取和判断请求头部信息
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取头部信息 */
|
||||
public HashMapSS getHeaders();
|
||||
|
||||
/** 获取请求头属性 */
|
||||
public String getHeader(String key);
|
||||
|
||||
/** 获取请求内容长度 */
|
||||
public int getContentLength();
|
||||
|
||||
/** 获取请求内容类型 */
|
||||
public String getContentType();
|
||||
|
||||
/** 获取请求要求的类型 */
|
||||
public String getMimeType();
|
||||
|
||||
/** 判断是否表单提交 */
|
||||
public boolean isMimeForm();
|
||||
|
||||
/** 判断是否文本请求 */
|
||||
public boolean isMimeTextPlain();
|
||||
|
||||
/** 设置请求的编码格式 */
|
||||
public void setCharacterEncoding(String characterEncoding);
|
||||
|
||||
/** 获取请求要求的编码,如果未设置默认UTF-8 */
|
||||
public String getCharacterEncoding();
|
||||
|
||||
/** 获取请求头中的编码,如果未设置默认null */
|
||||
public String getCharacterEncodingHeader();
|
||||
|
||||
/** 是否请求内容GZIP */
|
||||
public boolean isRequestGZip();
|
||||
|
||||
/** 是否响应支持GZIP */
|
||||
public boolean isResponseGZip();
|
||||
}
|
||||
@@ -0,0 +1,971 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
|
||||
import org.zhiqim.httpd.constants.HttpStep;
|
||||
import org.zhiqim.kernel.extend.HashMapSS;
|
||||
import org.zhiqim.kernel.logging.Log;
|
||||
import org.zhiqim.kernel.logging.LogFactory;
|
||||
import org.zhiqim.kernel.util.Bytes;
|
||||
import org.zhiqim.kernel.util.Strings;
|
||||
import org.zhiqim.kernel.util.Validates;
|
||||
import org.zhiqim.kernel.util.codes.URI;
|
||||
import org.zhiqim.kernel.util.seqs.Sequence;
|
||||
|
||||
/**
|
||||
* HTTP头部抽象类
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2018-9-11 新建与整理
|
||||
*/
|
||||
public abstract class HttpHeaderAbs extends HttpHeaderInner implements HttpHeader
|
||||
{
|
||||
private static final Log log = LogFactory.getLog("http.request");
|
||||
private static final Sequence sequence = new Sequence(6);
|
||||
|
||||
//连接&监听&输入输出流&发送器
|
||||
private HttpConnection conn;
|
||||
private HttpListener listener;
|
||||
private HttpServer server;
|
||||
|
||||
private HttpInputStream input;
|
||||
private HttpOutputStream output;
|
||||
private HttpSenderImpl sender;
|
||||
|
||||
//编号&步骤&时间
|
||||
private String requestId;
|
||||
private int requestStep;
|
||||
private long requestTimeMillis;
|
||||
|
||||
//状态
|
||||
private String statusLine;
|
||||
private String method;
|
||||
private URI uri;
|
||||
private String version;
|
||||
|
||||
//属性
|
||||
private HashMapSS headerMap;
|
||||
private String x_Forwarded_For;
|
||||
private String mimeType;
|
||||
private String characterEncoding;
|
||||
private X509Certificate[] certs;
|
||||
|
||||
//关联对象
|
||||
private HttpContext context;
|
||||
|
||||
//请求&响应&处理器
|
||||
private HttpRequestAbs request;
|
||||
private HttpResponseImpl response;
|
||||
private HttpHandler handler;
|
||||
|
||||
//临时路径值
|
||||
private transient String pathInContext;
|
||||
private transient String pathOnResource;
|
||||
|
||||
//解释头
|
||||
private List<String> headerList;
|
||||
private byte[] headerBuf = new byte[_MAX_LINE_LEN_ * 2];
|
||||
private boolean isCR=false,isLF=false,isCR2=false;
|
||||
private int pos=0, totalPos=0;
|
||||
|
||||
/** 构造函数 */
|
||||
public HttpHeaderAbs (HttpConnection conn, HttpInputStream input, SSLEngine sslEngine)
|
||||
{
|
||||
this.conn = conn;
|
||||
this.listener = conn.getListener();
|
||||
this.server = listener.getServer();
|
||||
this.input = input;
|
||||
this.output = new HttpOutputStream(conn);
|
||||
this.sender = newSender();
|
||||
|
||||
this.requestId = conn.getId() + sequence.nextString();
|
||||
this.requestStep = _01_CREATE_;
|
||||
this.requestTimeMillis = System.currentTimeMillis();
|
||||
|
||||
this.headerList = new ArrayList<String>();
|
||||
this.headerMap = new HashMapSS();
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
//子类必须实现的抽象方法
|
||||
/*****************************************************************************/
|
||||
|
||||
/** 创建发送器 */
|
||||
public abstract HttpSenderImpl newSender();
|
||||
|
||||
/** 创建请求 */
|
||||
public abstract HttpRequestAbs newRequest();
|
||||
|
||||
/** 是否BIO */
|
||||
public abstract boolean isBio();
|
||||
|
||||
/*****************************************************************************/
|
||||
//子类必须实现的抽象方法
|
||||
/*****************************************************************************/
|
||||
|
||||
public HttpServer getServer()
|
||||
{
|
||||
return server;
|
||||
}
|
||||
|
||||
public HttpContext getContext()
|
||||
{
|
||||
return context;
|
||||
}
|
||||
|
||||
public HttpInputStream getInputStream()
|
||||
{
|
||||
return input;
|
||||
}
|
||||
|
||||
public HttpOutputStream getOutputStream()
|
||||
{
|
||||
return output;
|
||||
}
|
||||
|
||||
public String getId()
|
||||
{
|
||||
return requestId;
|
||||
}
|
||||
|
||||
public long getReceiveTimeMillis()
|
||||
{
|
||||
return requestTimeMillis;
|
||||
}
|
||||
|
||||
public HttpListener getListener()
|
||||
{
|
||||
return listener;
|
||||
}
|
||||
|
||||
public HttpResponse getResponse()
|
||||
{
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override /** 获取连接中的日志对象 */
|
||||
public Log getLog()
|
||||
{
|
||||
return log;
|
||||
}
|
||||
|
||||
@Override /** 获取发送器 */
|
||||
public HttpSender getSender()
|
||||
{
|
||||
return sender;
|
||||
}
|
||||
|
||||
@Override /** 读取可配置值 */
|
||||
public String getConfiguration()
|
||||
{
|
||||
return context.getConfiguration();
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
//执行请求
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* 执行缓冲请求
|
||||
*
|
||||
* @exception HttpException HTTP异常
|
||||
* @exception IOException IO异常
|
||||
*/
|
||||
public boolean execute() throws HttpException, IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
//2.第二步,从流中解析消息头
|
||||
if (requestStep < _02_PARSE_HEADER_)
|
||||
{
|
||||
if (!parseHeaderStream())
|
||||
return true;//解析未完成情况,等待下次execute
|
||||
|
||||
setStep(_02_PARSE_HEADER_);
|
||||
}
|
||||
|
||||
//3.第三步,检查消息头
|
||||
if (requestStep < _03_CHECK_HEADER_)
|
||||
{
|
||||
parseHeader();
|
||||
sender.setVersion(getVersion());
|
||||
if (!isBio())
|
||||
{//非BIO根据请求来判断
|
||||
sender.setHeader(_CONNECTION_, getHeader(_CONNECTION_));
|
||||
}
|
||||
setStep(_03_CHECK_HEADER_);
|
||||
}
|
||||
|
||||
//4.第五步,查询上下文环境
|
||||
if (requestStep < _04_QUERY_CONTEXT_)
|
||||
{
|
||||
String host = getHostOnly();
|
||||
if (Validates.isEmpty(host))
|
||||
throw new HttpException(_412_PRECONDITION_FAILED_);
|
||||
|
||||
String path = getPath();
|
||||
|
||||
//4.1检查完全匹配,如http://www.zhiqim.com/example 对应到/example上下文环境
|
||||
context = server.getContext(host, path);
|
||||
if (context != null && !"/".equals(path))
|
||||
{//如果找到Context,则认为path是虚拟目录/example,重定向到Context的根http://example.zhiqim.com/
|
||||
sender.sendRedirect(path+"/");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (context == null)
|
||||
{//4.2检查是否有虚拟目录上下文环境
|
||||
String maybe = getVirtualDirectory();//虚拟目录
|
||||
context = server.getContext(host, maybe);
|
||||
if (context == null)
|
||||
{//不是虚拟目录上下文环境
|
||||
context = server.getContext(host, "/");
|
||||
}
|
||||
}
|
||||
|
||||
if (context == null)
|
||||
{//4.3未找到则表示未配置该上下文环境,返回未找到
|
||||
sender.sendError(_404_NOT_FOUND_);
|
||||
return true;
|
||||
}
|
||||
|
||||
setStep(_04_QUERY_CONTEXT_);
|
||||
}
|
||||
|
||||
//5.第五步,在上下文环境中查找处理器
|
||||
if (requestStep < _05_QUERY_HANDLER_)
|
||||
{
|
||||
parsePathInContext(context);
|
||||
String pathInContext = getPathInContext();
|
||||
if ("/".equals(pathInContext))
|
||||
{//5.1路径为根路径,但没匹配到欢迎页,返回未找到
|
||||
sender.sendError(_404_NOT_FOUND_);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (context.isFilterPath(pathInContext))
|
||||
{//5.2路径为过滤地址,返回禁止访问
|
||||
sender.sendError(_403_FORBIDDEN_);
|
||||
return true;
|
||||
}
|
||||
|
||||
//指定输出块大小
|
||||
output.setChunkSize(context.getChunkSize());
|
||||
|
||||
handler = context.getMatchHandler(pathInContext);
|
||||
if (handler == null)
|
||||
{//5.3未找到匹配的处理器
|
||||
context.handleResource(this, sender);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isMethodHead())
|
||||
{//5.4针对HEAD的请求直接返回成功即可
|
||||
sender.sendHeader(_200_OK_);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (handler instanceof HttpEntity)
|
||||
{//5.5找到是实体处理器
|
||||
((HttpEntity)handler).handle(this, sender);
|
||||
return true;
|
||||
}
|
||||
|
||||
setStep(_05_QUERY_HANDLER_);
|
||||
}
|
||||
|
||||
//6.第六步,解析GET,POST COOKIE,SESSION和内容等信息
|
||||
if (requestStep < _06_PARSE_CONTENT_)
|
||||
{
|
||||
if (request == null)
|
||||
request = newRequest();
|
||||
|
||||
if (response == null)
|
||||
response = new HttpResponseImpl(this.request);
|
||||
|
||||
request.parseHeaderByContextOK();
|
||||
request.parseGetPostCookieSession();
|
||||
if (!request.parseContent())
|
||||
return true;
|
||||
|
||||
setStep(_06_PARSE_CONTENT_);
|
||||
}
|
||||
|
||||
//7.第七步,转入处理器进行处理
|
||||
if (requestStep < _07_HANDLER_BEGIN_)
|
||||
{
|
||||
//BEGIN
|
||||
setStep(_07_HANDLER_BEGIN_);
|
||||
|
||||
HttpExecutor executor = (HttpExecutor)handler;
|
||||
executor.handle(request, response);
|
||||
|
||||
//END
|
||||
if (requestStep < _10_HANDLER_END_)
|
||||
setStep(_10_HANDLER_END_);
|
||||
}
|
||||
|
||||
//12.第十二步,提交
|
||||
if (!isCommitted())
|
||||
{
|
||||
if (response != null)
|
||||
response.commit();
|
||||
else
|
||||
sender.commit();
|
||||
}
|
||||
|
||||
return !isWebSocket();
|
||||
}
|
||||
catch (SSLHandshakeException e)
|
||||
{//SSL握手异常
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
catch(EOFException e)
|
||||
{//没读到消息
|
||||
try{sender.sendError(_400_BAD_REQUEST_);}catch(Exception e2){close();}
|
||||
return false;
|
||||
}
|
||||
catch(SocketTimeoutException | SocketException e)
|
||||
{//SOCKET异常
|
||||
try{sender.sendError(_408_REQUEST_TIMEOUT_);}catch(Exception e2){close();}
|
||||
return false;
|
||||
}
|
||||
catch(HttpException e)
|
||||
{//HTTP异常
|
||||
if (e.getCode() == _444_INTERRUPT_)
|
||||
close();//直接关闭
|
||||
else
|
||||
try{sender.sendError(e.getCode());}catch(Exception e2){close();}
|
||||
return false;
|
||||
}
|
||||
catch(IOException e)
|
||||
{//IO异常
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
catch(Throwable e)
|
||||
{//未知服务端异常
|
||||
log.error(e);
|
||||
try{sender.sendError(_500_INTERNAL_SERVER_ERROR_);}catch(Exception e2){close();}
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (isCommitted())
|
||||
{//已提交和关闭状态的清理及日志打印
|
||||
setStep(_12_FINISHED_);
|
||||
|
||||
listener.finished(this);
|
||||
|
||||
destroy();
|
||||
|
||||
if (sender != null){
|
||||
sender.destroy();
|
||||
}
|
||||
|
||||
if (request != null){
|
||||
request.destroy();
|
||||
}
|
||||
if (response != null){
|
||||
response.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 解析全路径path,生成上下文环境中绝对路径 */
|
||||
public void parsePathInContext(HttpContext context)
|
||||
{
|
||||
this.context = context;
|
||||
String contextPath = context.getContextPath();
|
||||
|
||||
if ("/".equals(contextPath))
|
||||
pathInContext = uri.getPath();
|
||||
else
|
||||
pathInContext = uri.getPath().substring(contextPath.length());
|
||||
pathInContext = Strings.addStartsWith(pathInContext, "/");
|
||||
|
||||
if ("/".equals(pathInContext))
|
||||
{//如果是根地址,则加上可能的welcomeUrl
|
||||
if (Validates.isNotEmptyBlank(context.getWelcomeUrl()))
|
||||
pathInContext = context.getWelcomeUrl();
|
||||
}
|
||||
|
||||
//设置编码格式
|
||||
if (Validates.isEmptyBlank(characterEncoding))
|
||||
characterEncoding = context.getDefaultEncoding();
|
||||
|
||||
if (Validates.isEmptyBlank(characterEncoding))
|
||||
characterEncoding = _UTF_8_;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分析请求行和请求头信息
|
||||
*
|
||||
* @param headerList 消息头列表,不为空
|
||||
* @exception EOFException 流结束异常
|
||||
* @exception HttpException HTTP请求异常
|
||||
*/
|
||||
public void parseHeader() throws EOFException, HttpException
|
||||
{
|
||||
//第一步,读头部流,得到头部列表
|
||||
if (headerList.isEmpty())
|
||||
throw new EOFException();
|
||||
|
||||
//第二步,检查首行格式,得到HTTP版本,方法和URL,如GET /index.htm HTTP/1.1
|
||||
String line = statusLine = headerList.get(0).trim();
|
||||
if (line.length() > _MAX_LINE_LEN_)
|
||||
throw new HttpException(_414_REQUEST_URL_TOO_LARGE_);
|
||||
|
||||
int ind = line.indexOf(' ');
|
||||
if (ind == -1)
|
||||
throw new HttpException(_400_BAD_REQUEST_);
|
||||
|
||||
//2.1,判断方法是不是仅支持的GET,POST和HEAD
|
||||
method = line.substring(0, ind);
|
||||
if (!(_GET_.equalsIgnoreCase(method) || _POST_.equalsIgnoreCase(method) || _HEAD_.equalsIgnoreCase(method)))
|
||||
throw new HttpException(_405_METHOD_NOT_ALLOWD_);
|
||||
method = method.toUpperCase();
|
||||
|
||||
line = line.substring(ind+1).trim();
|
||||
ind = line.indexOf(' ');
|
||||
if (ind == -1)
|
||||
throw new HttpException(_400_BAD_REQUEST_);
|
||||
|
||||
//2.2,读取URL
|
||||
String url = line.substring(0, ind);
|
||||
if (url == null || url.trim().length()<1)
|
||||
throw new HttpException(_400_BAD_REQUEST_);
|
||||
|
||||
if (!url.startsWith("/") || url.indexOf("/..") != -1 || url.indexOf("../") != -1)//如果出现目录相关的,直接拒绝
|
||||
throw new HttpException(_400_BAD_REQUEST_);
|
||||
|
||||
//2.3,解析URL成URI
|
||||
uri = new URI();
|
||||
if (!uri.parseUri(url.trim()))
|
||||
throw new HttpException(_400_BAD_REQUEST_);
|
||||
|
||||
//2.4,判断HTTP版本是否是支持的1.0/1.1
|
||||
version = line.substring(ind+1).trim();
|
||||
if (!_HTTP_1_1_.equals(version) && !_HTTP_1_0_.equals(version))
|
||||
throw new HttpException(_505_VERSION_NOT_SUPPORTED_);
|
||||
|
||||
//第三步,读取其他头部信息
|
||||
for (int i=1;i<headerList.size();i++)
|
||||
{
|
||||
line = headerList.get(i);
|
||||
ind = line.indexOf(':');
|
||||
if (ind == -1)
|
||||
continue;
|
||||
|
||||
String key = Strings.trim(line.substring(0, ind));
|
||||
String value = Strings.trim(line.substring(ind+1));
|
||||
setHeader(key, value);
|
||||
}
|
||||
|
||||
//第四步,检查是否是代理模式
|
||||
|
||||
//4.1,如果不是代理模式则返结束
|
||||
x_Forwarded_For = getHeader(_X_FORWARDED_FOR_);
|
||||
|
||||
//4.2,把真实HOST放置到_HOST_
|
||||
String x_Forwarded_Host = getHeader(_X_FORWARDED_HOST_);
|
||||
if (Validates.isNotEmptyBlank(x_Forwarded_Host))
|
||||
setHeader(_HOST_, x_Forwarded_Host);
|
||||
|
||||
//第五步,验证HOST是否是服务端支持的
|
||||
String hostPort = getHostPort();
|
||||
if (hostPort == null)
|
||||
throw new HttpException(_412_PRECONDITION_FAILED_);
|
||||
|
||||
//第六步,获取内容格式和编码,如果不存在内容类型则默认为UTF-8
|
||||
String contentType= getHeader(_CONTENT_TYPE_);
|
||||
if (contentType != null)
|
||||
{
|
||||
//在contentType中查找encoding,格式为:text/html; charset=UTF-8; boundary=-------123456789
|
||||
int i0 = contentType.indexOf(';');
|
||||
if (i0 == -1)
|
||||
mimeType = contentType.toLowerCase();
|
||||
else
|
||||
{
|
||||
mimeType = contentType.substring(0, i0).trim().toLowerCase();
|
||||
int i1 = contentType.indexOf("charset=", i0);
|
||||
if (i1>=0)
|
||||
{
|
||||
int i2 = contentType.indexOf(";", i1);
|
||||
if (i2 == -1)
|
||||
characterEncoding = contentType.substring(i1 + 8);
|
||||
else
|
||||
characterEncoding = contentType.substring(i1 + 8, i2).trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** 分析头部流 */
|
||||
private boolean parseHeaderStream() throws HttpException, IOException
|
||||
{
|
||||
int b = input.read();
|
||||
while (b != -1)
|
||||
{
|
||||
if (totalPos > _MAX_LINE_LEN_ * _MAX_HEADER_LINE_)//头部总大小不超过128行最大值
|
||||
throw new HttpException(_414_REQUEST_URL_TOO_LARGE_);
|
||||
|
||||
if (pos > _MAX_LINE_LEN_)//单行总大小不超过8192
|
||||
throw new HttpException(_414_REQUEST_URL_TOO_LARGE_);
|
||||
|
||||
if (b == _CR_)
|
||||
{//回车
|
||||
pos = 0;//指定回首位置
|
||||
String line = Bytes.BI.getString(headerBuf, 0, (byte)0);
|
||||
if (line != null && line.trim().length() > 0)
|
||||
headerList.add(line);
|
||||
|
||||
Bytes.fillBytes(headerBuf, 0, (byte)0, _MAX_LINE_LEN_ * 2);
|
||||
if (isCR)
|
||||
isCR2 = true;
|
||||
else
|
||||
isCR = true;
|
||||
}
|
||||
else if (b== _LF_)
|
||||
{//换行
|
||||
if (isCR && isLF && isCR2)
|
||||
break;//头部结束
|
||||
else
|
||||
isLF = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
isCR = isLF = isCR2 = false;//恢复标志
|
||||
headerBuf[pos++] = (byte)b;
|
||||
totalPos++;
|
||||
}
|
||||
|
||||
b = input.read();
|
||||
}
|
||||
|
||||
return (isCR && isLF && isCR2);
|
||||
}
|
||||
|
||||
/*******************************************************************************/
|
||||
//步骤
|
||||
/*******************************************************************************/
|
||||
|
||||
public void setStep(int step)
|
||||
{
|
||||
if (this.requestStep >= step)
|
||||
return;
|
||||
|
||||
this.requestStep = step;
|
||||
}
|
||||
|
||||
public int getStep()
|
||||
{
|
||||
return requestStep;
|
||||
}
|
||||
|
||||
public String getStepDesc()
|
||||
{
|
||||
return HttpStep.getStatusMsg(requestStep);
|
||||
}
|
||||
|
||||
public boolean isRead()
|
||||
{//头部已读
|
||||
return requestStep > _03_CHECK_HEADER_;
|
||||
}
|
||||
|
||||
public boolean isParsed()
|
||||
{//内部已读
|
||||
return requestStep > _06_PARSE_CONTENT_;
|
||||
}
|
||||
|
||||
public boolean isHandled()
|
||||
{//处理完成
|
||||
return requestStep >= _10_HANDLER_END_;
|
||||
}
|
||||
|
||||
public boolean isCommitted()
|
||||
{//提交完成
|
||||
return requestStep >= _11_COMMITTED_;
|
||||
}
|
||||
|
||||
public boolean isEditable()
|
||||
{//正在提交即不可编辑
|
||||
return !isCommitted();
|
||||
}
|
||||
|
||||
/** 关闭连接 */
|
||||
public void close()
|
||||
{//由sender回调
|
||||
if (!isCommitted())
|
||||
setStep(_11_COMMITTED_);
|
||||
|
||||
conn.close();
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
//获取和判断请求行信息,包括协议、方法、版本、URI等
|
||||
/***********************************************************************/
|
||||
|
||||
@Override /** 获取客户端IP地址 */
|
||||
public String getRemoteAddr()
|
||||
{
|
||||
//如果是代理,取代理第一个IP
|
||||
if (x_Forwarded_For != null)
|
||||
return x_Forwarded_For.split(",")[0];
|
||||
else//否则取连接
|
||||
return conn.getRemoteAddr();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getListenerPort()
|
||||
{
|
||||
return conn.getListener().getPort();
|
||||
}
|
||||
|
||||
@Override /** 获取请求行 */
|
||||
public String getHeaderLine()
|
||||
{
|
||||
return statusLine;
|
||||
}
|
||||
|
||||
@Override /** 获取请求版本 */
|
||||
public String getVersion()
|
||||
{
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override /** 获取请求方法 */
|
||||
public String getMethod()
|
||||
{
|
||||
return method;
|
||||
}
|
||||
|
||||
@Override /** 是否是HEAD方法 */
|
||||
public boolean isMethodHead()
|
||||
{
|
||||
return _HEAD_.equals(method);
|
||||
}
|
||||
|
||||
@Override /** 是否是GET方法 */
|
||||
public boolean isMethodGet()
|
||||
{
|
||||
return _GET_.equals(method);
|
||||
}
|
||||
|
||||
@Override /** 是否是POST方法 */
|
||||
public boolean isMethodPost()
|
||||
{
|
||||
return _POST_.equals(method);
|
||||
}
|
||||
|
||||
@Override /** 判断是否需要响应内容 */
|
||||
public boolean isMethodResponseContent()
|
||||
{//GET,POST,其他的PUT,DELETE认为是增加和删除,只响应状态
|
||||
return _GET_.equals(method) || _POST_.equals(method);
|
||||
}
|
||||
|
||||
/** 获取URI信息 */
|
||||
public URI getUri()
|
||||
{
|
||||
return uri;
|
||||
}
|
||||
|
||||
@Override /** 获取URI路径,以/开头,如/test.html,如果没有文件后缀则为'/' */
|
||||
public String getPath()
|
||||
{
|
||||
return (uri == null)?"":uri.getPath();
|
||||
}
|
||||
|
||||
@Override /** 获取查询串 */
|
||||
public String getQueryString()
|
||||
{
|
||||
return uri.getQuery();
|
||||
}
|
||||
|
||||
@Override /** 获取URI虚拟目录信息 */
|
||||
public String getVirtualDirectory()
|
||||
{
|
||||
return uri.getVirtualDirectory();
|
||||
}
|
||||
|
||||
@Override /** 获取头部信息 */
|
||||
public HashMapSS getHeaders()
|
||||
{
|
||||
return headerMap;
|
||||
}
|
||||
|
||||
/** 设置头部信息,KEY统一使用小写 */
|
||||
public void setHeader(String key, String value)
|
||||
{
|
||||
headerMap.put(key.toLowerCase(), value);
|
||||
}
|
||||
|
||||
@Override /** 获取请求头属性 */
|
||||
public String getHeader(String key)
|
||||
{
|
||||
return headerMap.get(key.toLowerCase());
|
||||
}
|
||||
|
||||
@Override /** 获取请求头中的编码,如果未设置默认null */
|
||||
public String getCharacterEncodingHeader()
|
||||
{
|
||||
String contentType= getHeader(_CONTENT_TYPE_);
|
||||
if (Validates.isEmptyBlank(contentType))
|
||||
return null;
|
||||
|
||||
contentType = contentType.toLowerCase();
|
||||
int i1 = contentType.indexOf("charset=");
|
||||
if (i1 == -1)
|
||||
return null;
|
||||
|
||||
int i2 = contentType.indexOf(";", i1);
|
||||
if (i2 == -1)
|
||||
return contentType.substring(i1 + 8);
|
||||
else
|
||||
return contentType.substring(i1 + 8, i2).trim();
|
||||
}
|
||||
|
||||
/** 获取请求内容长度 */
|
||||
public int getContentLength()
|
||||
{
|
||||
String sLen = getHeader(_CONTENT_LENGTH_);
|
||||
if (!Validates.isInteger(sLen))
|
||||
return 0;
|
||||
return Integer.parseInt(sLen);
|
||||
}
|
||||
|
||||
/** 获取请求内容类型 */
|
||||
public String getContentType()
|
||||
{
|
||||
return getHeader(_CONTENT_TYPE_);
|
||||
}
|
||||
|
||||
/** 获取请求要求的类型 */
|
||||
public String getMimeType()
|
||||
{
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
/** 判断是否表单提交 */
|
||||
public boolean isMimeForm()
|
||||
{
|
||||
return _APPLICATION_X_WWW_FORM_.equals(mimeType);
|
||||
}
|
||||
|
||||
/** 判断是否文本请求 */
|
||||
public boolean isMimeTextPlain()
|
||||
{
|
||||
return _TEXT_PLAIN_.equals(mimeType);
|
||||
}
|
||||
|
||||
/** 设置请求的编码格式 */
|
||||
public void setCharacterEncoding(String characterEncoding)
|
||||
{
|
||||
if (Validates.isEmptyBlank(characterEncoding))
|
||||
return;//不支持设置空白编码格式
|
||||
|
||||
this.characterEncoding = characterEncoding;
|
||||
}
|
||||
|
||||
/** 获取请求要求的编码,如果未设置默认UTF-8 */
|
||||
public String getCharacterEncoding()
|
||||
{
|
||||
return characterEncoding;
|
||||
}
|
||||
|
||||
/** 获取HOST:PORT */
|
||||
public String getHostPort()
|
||||
{
|
||||
return getHeader(_HOST_);
|
||||
}
|
||||
|
||||
/** 如果有PORT仅取HOST */
|
||||
public String getHostOnly()
|
||||
{
|
||||
String hostPort = getHostPort();
|
||||
if (Validates.isEmpty(hostPort))
|
||||
return null;
|
||||
|
||||
int ind = hostPort.indexOf(":");
|
||||
if (ind == -1)
|
||||
return hostPort;
|
||||
else//去除:之间的空格
|
||||
return Strings.trim(hostPort.substring(0, ind));
|
||||
}
|
||||
|
||||
/** 获取浏览器代理 */
|
||||
public String getUserAgent()
|
||||
{
|
||||
return getHeader(_USER_AGENT_);
|
||||
}
|
||||
|
||||
/** 是否请求内容GZIP */
|
||||
public boolean isRequestGZip()
|
||||
{
|
||||
String contentEncoding = getHeader(_CONTENT_ENCODING_);
|
||||
return _ENCODING_GZIP_.equalsIgnoreCase(contentEncoding);
|
||||
}
|
||||
|
||||
/** 是否响应支持GZIP */
|
||||
public boolean isResponseGZip()
|
||||
{
|
||||
String acceptEncoding = getHeader(_ACCEPT_ENCODING_);
|
||||
if (Validates.isEmpty(acceptEncoding) || acceptEncoding.indexOf(_ENCODING_GZIP_) == -1)
|
||||
return false;
|
||||
|
||||
String userAgent = getUserAgent();
|
||||
if (Validates.isEmpty(userAgent) || userAgent.toLowerCase().indexOf("msie 6.0") > -1)
|
||||
return false;//IE6,有部分浏览器有问题可能不支持GZIP
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getXForwardedFor()
|
||||
{
|
||||
return x_Forwarded_For;
|
||||
}
|
||||
|
||||
public void setCertificates(X509Certificate[] certs)
|
||||
{
|
||||
this.certs = certs;
|
||||
}
|
||||
|
||||
public X509Certificate[] getCertificates()
|
||||
{
|
||||
return certs;
|
||||
}
|
||||
|
||||
/** 是否是Websocket协议 */
|
||||
public boolean isWebSocket()
|
||||
{
|
||||
return _WEBSOCKET_.equalsIgnoreCase(getHeader(_UPGRADE_)) && Strings.contains(getHeader(_CONNECTION_).toLowerCase(), _UPGRADE_.toLowerCase());
|
||||
}
|
||||
|
||||
/** 由转向时设置新的地址 */
|
||||
public void setPathInContext(String pathInContext)
|
||||
{
|
||||
pathInContext = Strings.addStartsWith(pathInContext, "/");
|
||||
|
||||
if ("/".equals(pathInContext))
|
||||
{//如果是根地址,则加上可能的welcomeUrl
|
||||
if (Validates.isNotEmptyBlank(context.getWelcomeUrl()))
|
||||
pathInContext = context.getWelcomeUrl();
|
||||
}
|
||||
|
||||
this.pathInContext = pathInContext;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
//在找到HttpContext时才有效
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取HTTP连接 */
|
||||
public HttpConnection getConnection()
|
||||
{
|
||||
return conn;
|
||||
}
|
||||
|
||||
/** 获取在上下文环境下的路径 */
|
||||
public String getPathInContext()
|
||||
{
|
||||
return pathInContext;
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
//由ClassResourceHandler和FileResourceHandler处理的资源临时文件路径
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取资源文件下绝对路径 */
|
||||
public String getPathOnResource()
|
||||
{
|
||||
return pathOnResource;
|
||||
}
|
||||
|
||||
/** 设置资源文件下绝对路径 ,由context回调 */
|
||||
public void setPathOnResource(String pathOnResource)
|
||||
{
|
||||
this.pathOnResource = pathOnResource;
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
//toString & destroy
|
||||
/***********************************************************************/
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder strb = new StringBuilder();
|
||||
strb.append(statusLine).append(_BR_);
|
||||
if (headerMap != null)
|
||||
{
|
||||
for (Entry<String, String> entry : headerMap.entrySet())
|
||||
{
|
||||
strb.append(entry.getKey()).append(_COLON_).append(entry.getValue()).append(_BR_);
|
||||
}
|
||||
strb.append(_BR_);
|
||||
}
|
||||
return strb.toString();
|
||||
}
|
||||
|
||||
private void destroy()
|
||||
{
|
||||
if (headerMap != null)
|
||||
{
|
||||
headerMap.clear();
|
||||
headerMap = null;
|
||||
}
|
||||
|
||||
if (headerList != null)
|
||||
{
|
||||
headerList.clear();
|
||||
headerList = null;
|
||||
}
|
||||
|
||||
//引用置空
|
||||
statusLine = null;
|
||||
method = null;
|
||||
uri = null;
|
||||
version = null;
|
||||
x_Forwarded_For = null;
|
||||
mimeType = null;
|
||||
characterEncoding = null;
|
||||
|
||||
conn = null;
|
||||
context = null;
|
||||
pathInContext = null;
|
||||
pathOnResource = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
/**
|
||||
* HTTP请求头内部接口
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2018-9-22 新建与整理
|
||||
*/
|
||||
public abstract class HttpHeaderInner
|
||||
{
|
||||
/** 设置资源文件下绝对路径 ,由context回调 */
|
||||
public abstract void setPathOnResource(String pathOnResource);
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.zhiqim.kernel.util.Asserts;
|
||||
|
||||
/**
|
||||
* HTTP阻塞式输入流
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public class HttpInputStream extends InputStream
|
||||
{
|
||||
private InputStream input;
|
||||
private ByteBuffer buffer;
|
||||
|
||||
public HttpInputStream()
|
||||
{
|
||||
}
|
||||
|
||||
public HttpInputStream(InputStream input)
|
||||
{
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
//NIO使用的缓冲
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* 增加缓冲数据,检查是否在起始位置,不在会作flip
|
||||
*
|
||||
* @param buf 字节缓冲
|
||||
*/
|
||||
public synchronized void addBuffer(ByteBuffer buf)
|
||||
{
|
||||
Asserts.as(input == null?null:"已有输入流,不支持增加缓冲数据");
|
||||
|
||||
if (buf.position() != 0)
|
||||
{//新增加的没作flip操作的
|
||||
buf.flip();
|
||||
}
|
||||
|
||||
if (!buf.hasRemaining())
|
||||
{//没有数据不处理
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer == null)
|
||||
{
|
||||
buffer = ByteBuffer.allocate(buf.remaining());
|
||||
buffer.put(buf).flip();
|
||||
}
|
||||
else
|
||||
{
|
||||
ByteBuffer nBuf = ByteBuffer.allocate(buffer.remaining() + buf.remaining());
|
||||
nBuf.put(buffer).put(buf).flip();
|
||||
buffer = nBuf;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized byte[] read(int len)
|
||||
{
|
||||
Asserts.as(input == null?null:"已有输入流,不支持该方法调用");
|
||||
|
||||
if (buffer == null)
|
||||
return new byte[0];
|
||||
|
||||
int length = buffer.remaining();
|
||||
if (length <= 0)
|
||||
return new byte[0];
|
||||
|
||||
int count = length <= len?length:len;
|
||||
byte[] buf = new byte[count];
|
||||
buffer.get(buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
//NIO/BIO共用的InputStream方法
|
||||
/*****************************************************************************/
|
||||
|
||||
public synchronized int read() throws IOException
|
||||
{
|
||||
if (input != null)
|
||||
return input.read();
|
||||
|
||||
if (buffer == null || !buffer.hasRemaining())
|
||||
return -1;
|
||||
|
||||
try{return buffer.get();}catch(BufferUnderflowException e){return -1;}
|
||||
}
|
||||
|
||||
public synchronized int read(byte[] b, int off, int len) throws IOException
|
||||
{
|
||||
if (input != null)
|
||||
return input.read(b, off, len);
|
||||
|
||||
if (buffer == null || !buffer.hasRemaining())
|
||||
return -1;
|
||||
|
||||
int pos = buffer.position();
|
||||
buffer.get(b, off, len);
|
||||
return buffer.position() - pos;
|
||||
}
|
||||
|
||||
public synchronized int read(byte[] b) throws IOException
|
||||
{
|
||||
if (input != null)
|
||||
return input.read(b);
|
||||
|
||||
if (buffer == null || !buffer.hasRemaining())
|
||||
return -1;
|
||||
|
||||
int pos = buffer.position();
|
||||
buffer.get(b);
|
||||
return buffer.position() - pos;
|
||||
}
|
||||
|
||||
public synchronized int available()
|
||||
{
|
||||
if (input != null)
|
||||
try{return input.available();}catch(IOException e){throw Asserts.exception(e);}
|
||||
|
||||
return buffer==null?-1:buffer.remaining();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,389 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.zhiqim.httpd.bio.HttpBioConnection;
|
||||
import org.zhiqim.httpd.nio.HttpNioConnection;
|
||||
import org.zhiqim.kernel.config.Group;
|
||||
import org.zhiqim.kernel.control.Queue;
|
||||
import org.zhiqim.kernel.control.ThreaderController;
|
||||
import org.zhiqim.kernel.control.Threadx;
|
||||
import org.zhiqim.kernel.logging.Log;
|
||||
import org.zhiqim.kernel.logging.LogFactory;
|
||||
import org.zhiqim.kernel.schedule.Interval;
|
||||
import org.zhiqim.kernel.schedule.Task;
|
||||
import org.zhiqim.kernel.util.Asserts;
|
||||
|
||||
/**
|
||||
* HTTP监听器接口定义
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public abstract class HttpListener extends Threadx implements Task, HttpdConstants
|
||||
{
|
||||
protected static final Log log = LogFactory.getLog(HttpListener.class);
|
||||
|
||||
private final HttpServer server; //服务器
|
||||
private final List<HttpConnection> connList; //连接列表
|
||||
|
||||
protected Group listenerGroup; //监听参数
|
||||
protected String listenerName; //监听名称
|
||||
protected int listenerPort; //监听端口
|
||||
protected String listenerIp; //监听网卡IP地址
|
||||
|
||||
protected int soTimeoutMs; //套接字等待连接时长,单位毫秒,等待60*1000秒
|
||||
protected int soLingerS; //套接字关闭连接时长,(TIME_WAIT和操作系统有关),单位秒,最大65535,即默认2MSL
|
||||
protected int soRecvBuf; //套接字接收缓冲区大小,默认KiB
|
||||
protected int soSendBuf; //套接字接收缓冲区大小,默认128KiB
|
||||
protected int soIdleTimeMs; //套接字长连接最大空闲时长,单位毫秒,默认53*1000毫秒
|
||||
|
||||
protected int poMinSize; //线程池最小值
|
||||
protected int poMaxSize; //线程池最大值
|
||||
protected int poIdleTime; //线程池线程空闲时长
|
||||
protected int poQueueSize; //线程池队列大小
|
||||
|
||||
protected ThreaderController controller; //线程池控制器
|
||||
protected Log logger; //日志记录器
|
||||
|
||||
private Interval interval; //定时器,检查超时连接
|
||||
|
||||
public HttpListener(HttpServer server)
|
||||
{
|
||||
this.server = server;
|
||||
this.connList = new ArrayList<>();
|
||||
}
|
||||
|
||||
public void setGroup(Group group)
|
||||
{
|
||||
this.listenerGroup = group;
|
||||
}
|
||||
|
||||
@Override /** 线程名 */
|
||||
protected String getThreadName()
|
||||
{
|
||||
return listenerName;
|
||||
}
|
||||
|
||||
@Override /** 线程开启前 */
|
||||
protected boolean openBefore()
|
||||
{
|
||||
listenerName = listenerGroup.getId();
|
||||
listenerIp = listenerGroup.getString(_LISTEN_IP_ADDRESS_);
|
||||
listenerPort = listenerGroup.getInt(_LISTEN_PORT_);
|
||||
Asserts.as((listenerPort >= 1 && listenerPort <= 65535)?null:"未配置[%s]的port配置项,或配置的值不是端口值[1-65535]");
|
||||
|
||||
soTimeoutMs = listenerGroup.getInt(_LISTEN_SO_ITMEOUT_, 60) * 1000;
|
||||
soLingerS = listenerGroup.getInt(_LISTEN_SO_LINGER_, -1);
|
||||
soRecvBuf = listenerGroup.getInt(_LISTEN_SO_RECV_BUF_, KiB);
|
||||
soSendBuf = listenerGroup.getInt(_LISTEN_SO_SEND_BUF_, 128 * KiB);
|
||||
soIdleTimeMs = listenerGroup.getInt(_LISTEN_SO_IDLE_TIME_, 53) * 1000;
|
||||
|
||||
poMinSize = listenerGroup.getInt(_LISTEN_PO_MIN_SIZE_, 20);
|
||||
poMaxSize = listenerGroup.getInt(_LISTEN_PO_MAX_SIZE_, 200);
|
||||
poIdleTime = listenerGroup.getInt(_LISTEN_PO_IDLE_TIME_, 600);
|
||||
poQueueSize = listenerGroup.getInt(_LISTEN_PO_QUEUE_SIZE_, poMaxSize * 3);
|
||||
|
||||
if (listenerGroup.isTrue(_LISTEN_ACCESS_LOG_))
|
||||
{//创建访问日志
|
||||
logger = LogFactory.getLog(listenerName);
|
||||
}
|
||||
|
||||
if (soIdleTimeMs > 0)
|
||||
{//配置的Socket时长则作定时检查
|
||||
interval = Interval.shedule(this, soIdleTimeMs);
|
||||
}
|
||||
|
||||
//初始化线程控制器
|
||||
controller = new ThreaderController();
|
||||
controller.set(poMinSize, poMaxSize, poIdleTime, poQueueSize);
|
||||
controller.setThreadName(listenerName);
|
||||
controller.create();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override /** 线程关闭后 */
|
||||
protected void closeAfter()
|
||||
{
|
||||
//1.关闭定时任务
|
||||
if (interval != null)
|
||||
{
|
||||
interval.close();
|
||||
interval = null;
|
||||
}
|
||||
|
||||
//2.关闭处理控制器
|
||||
if (controller != null)
|
||||
{
|
||||
controller.close();
|
||||
controller = null;
|
||||
}
|
||||
|
||||
//3.清理线程池
|
||||
connList.clear();
|
||||
|
||||
//4.打印退出日志
|
||||
log.info(toString() + "退出");
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
//通用实现方法
|
||||
/**************************************************************************/
|
||||
|
||||
/** 服务 */
|
||||
public HttpServer getServer()
|
||||
{
|
||||
return server;
|
||||
}
|
||||
|
||||
/** 协议 */
|
||||
public String getScheme()
|
||||
{
|
||||
return _HTTP_;
|
||||
}
|
||||
|
||||
/** 监听端口 */
|
||||
public int getPort()
|
||||
{
|
||||
return listenerPort;
|
||||
}
|
||||
|
||||
/** 监听名 */
|
||||
public String getName()
|
||||
{
|
||||
return listenerName;
|
||||
}
|
||||
|
||||
/** 监听网卡地址 */
|
||||
public String getIpAddress()
|
||||
{
|
||||
return listenerIp;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
//Socket参数
|
||||
/**************************************************************************/
|
||||
|
||||
/** Socket连接超时时长 */
|
||||
public int getSoTimeoutMs()
|
||||
{
|
||||
return soTimeoutMs;
|
||||
}
|
||||
|
||||
/** Socket接收缓冲大小 */
|
||||
public int getSoRecvBuf()
|
||||
{
|
||||
return soRecvBuf;
|
||||
}
|
||||
|
||||
/** Socket发送缓冲大小 */
|
||||
public int getSoSendBuf()
|
||||
{
|
||||
return soSendBuf;
|
||||
}
|
||||
|
||||
/** Socket长连接空闲时长 */
|
||||
public int getSoIdleTimeMs()
|
||||
{
|
||||
return soIdleTimeMs;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
//线程池参数,主要用于监控,请谨慎调用
|
||||
/**************************************************************************/
|
||||
|
||||
/** 线程池允许的最大值 */
|
||||
public int getPoMaxSize()
|
||||
{
|
||||
return poMaxSize;
|
||||
}
|
||||
|
||||
/** 线程池定义的最小值 */
|
||||
public int getPoMinSize()
|
||||
{
|
||||
return poMinSize;
|
||||
}
|
||||
|
||||
/** 线程池允许的最大队列数 */
|
||||
public int getPoQueueSize()
|
||||
{
|
||||
return poQueueSize;
|
||||
}
|
||||
|
||||
/** 线程池线程允许的空闲时长 */
|
||||
public int getPoIdleTime()
|
||||
{
|
||||
return poIdleTime;
|
||||
}
|
||||
|
||||
/** 线程池控制器 */
|
||||
public ThreaderController getController()
|
||||
{
|
||||
return controller;
|
||||
}
|
||||
|
||||
/** 线程池中当前活动数 */
|
||||
public int getThreaderActiveSize()
|
||||
{
|
||||
return controller.getThreaderActiveSize();
|
||||
}
|
||||
|
||||
/** 线程池当前大小 */
|
||||
public int getThreaderSize()
|
||||
{
|
||||
return controller.getThreaderSize();
|
||||
}
|
||||
|
||||
/** 线程池总完成数 */
|
||||
public long getCompletedCount()
|
||||
{
|
||||
return controller.getCompletedCount();
|
||||
}
|
||||
|
||||
/** 线程池当前队列 */
|
||||
public Queue<Runnable> getQueue()
|
||||
{
|
||||
return controller.getQueue();
|
||||
}
|
||||
|
||||
/** 线程池当前队列数 */
|
||||
public int getQueueSize()
|
||||
{
|
||||
return controller.size();
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
//监听下的连接完成
|
||||
/**************************************************************************/
|
||||
|
||||
/** 删除连接 */
|
||||
public void remove(HttpConnection conn)
|
||||
{
|
||||
synchronized (connList)
|
||||
{
|
||||
connList.remove(conn);
|
||||
}
|
||||
}
|
||||
|
||||
/** 增加连接 */
|
||||
protected HttpNioConnection add(HttpNioConnection conn)
|
||||
{
|
||||
synchronized (connList)
|
||||
{
|
||||
connList.add(conn);
|
||||
}
|
||||
return conn;
|
||||
}
|
||||
|
||||
/** 删除连接 */
|
||||
protected HttpBioConnection add(HttpBioConnection conn)
|
||||
{
|
||||
synchronized (connList)
|
||||
{
|
||||
connList.add(conn);
|
||||
}
|
||||
return conn;
|
||||
}
|
||||
|
||||
/** 线程池处理完记录日志 */
|
||||
public void finished(HttpHeader header)
|
||||
{
|
||||
if (logger == null)
|
||||
return;
|
||||
|
||||
//打印日志
|
||||
HttpSender sender = header.getSender();
|
||||
|
||||
String remoteAddr = header.getRemoteAddr();
|
||||
String headerLine = header.getHeaderLine();
|
||||
int listenerPort = header.getListenerPort();
|
||||
int status = sender.getStatus();
|
||||
|
||||
long length = 0;
|
||||
if (sender instanceof HttpSenderImpl)
|
||||
length = ((HttpSenderImpl)sender).getFlushLength();
|
||||
else if (sender instanceof HttpResponseImpl)
|
||||
length = ((HttpResponseImpl)sender).getFlushLength();
|
||||
|
||||
String message = new StringBuilder()
|
||||
.append("[").append(remoteAddr).append("]")
|
||||
.append(" [").append(status).append("]")
|
||||
.append(" [").append(listenerPort).append("]")
|
||||
.append(" [").append(length).append("]")
|
||||
.append(" [").append(headerLine).append("]")
|
||||
.toString();
|
||||
|
||||
logger.info(message);
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
//连接检查
|
||||
/**************************************************************************/
|
||||
|
||||
@Override /** 定义检查 */
|
||||
public void execute()
|
||||
{
|
||||
int wsNum = 0, activeNum = 0;
|
||||
List<HttpConnection> list = new ArrayList<>();
|
||||
synchronized (connList)
|
||||
{
|
||||
for (HttpConnection conn : connList)
|
||||
list.add(conn);
|
||||
}
|
||||
|
||||
for (HttpConnection conn : list)
|
||||
{
|
||||
if (conn.isWebsocket())
|
||||
{
|
||||
wsNum++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (conn.isActive())
|
||||
{
|
||||
activeNum++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (conn.isOvertime())
|
||||
{
|
||||
log.debug("连接[%s]空闲过长,正常关闭", conn.getId());
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
|
||||
int totalNum = list.size(), idleNum = totalNum - wsNum - activeNum;
|
||||
list.clear();list = null;
|
||||
log.info("允许最大连接[%s],当前总连接[%s]=WS[%s]+活动[%s]+空闲[%s],允许空闲[%s]秒", poMaxSize, totalNum, wsNum, activeNum, idleNum, soIdleTimeMs/1000);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return new StringBuilder(getScheme()).append("监听:[")
|
||||
.append("name:").append(listenerName).append(";")
|
||||
.append("port:").append(listenerPort).append("]")
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.zhiqim.kernel.util.Ints;
|
||||
import org.zhiqim.kernel.util.Zips;
|
||||
|
||||
|
||||
/**
|
||||
* HTTP阻塞式输入流,通过ByteArrayOutputStream实现header和content分隔
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public class HttpOutputStream extends OutputStream implements HttpdConstants
|
||||
{
|
||||
private final HttpOutputStreamWrap output;
|
||||
private int chunkSize = _MAX_CHUNKED_SIZE_;
|
||||
|
||||
private HttpSenderImpl sender;
|
||||
private ByteArrayOutputStream content;
|
||||
|
||||
private boolean chunked;
|
||||
private boolean headed;
|
||||
|
||||
public HttpOutputStream(HttpConnection conn)
|
||||
{
|
||||
this.output = new HttpOutputStreamWrap(conn);
|
||||
this.content = new ByteArrayOutputStream();
|
||||
}
|
||||
|
||||
public void setSender(HttpSenderImpl sender)
|
||||
{
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
public void setChunkSize(int chunkSize)
|
||||
{
|
||||
if (chunkSize < 4 * KiB)
|
||||
this.chunkSize = 4 * KiB;
|
||||
else if (chunkSize > _MAX_CHUNKED_SIZE_)
|
||||
this.chunkSize = _MAX_CHUNKED_SIZE_;
|
||||
else
|
||||
this.chunkSize = chunkSize;
|
||||
}
|
||||
|
||||
/*************************************************************************************/
|
||||
//继承和实现的方法
|
||||
/*************************************************************************************/
|
||||
|
||||
public void write(int b) throws IOException
|
||||
{
|
||||
if (sender.isCommitted())
|
||||
return;
|
||||
|
||||
if (content.size() >= chunkSize)
|
||||
{//上次最后满一次分块
|
||||
flush();
|
||||
}
|
||||
|
||||
content.write(b);
|
||||
}
|
||||
|
||||
public void write(byte[] b, int off, int len) throws IOException
|
||||
{
|
||||
if (sender.isCommitted())
|
||||
return;
|
||||
|
||||
if (content.size() >= chunkSize)
|
||||
{//上次最后满一次分块
|
||||
flush();
|
||||
}
|
||||
|
||||
if (content.size() + len <= chunkSize)
|
||||
{//不足或刚好一次分块,直接添加即可
|
||||
content.write(b, off, len);
|
||||
return;
|
||||
}
|
||||
|
||||
//超过分块数
|
||||
int page = (content.size() + len - 1) / chunkSize + 1;
|
||||
|
||||
//先写第一块,并刷入
|
||||
int firstLen = chunkSize - content.size();
|
||||
content.write(b, off, firstLen);
|
||||
flush();
|
||||
|
||||
//后续块
|
||||
int length = firstLen;
|
||||
for (int i=1;i<page;i++)
|
||||
{
|
||||
int count = (i<page-1)?chunkSize:len-length;
|
||||
content.write(b, off+length, count);
|
||||
length += count;
|
||||
|
||||
if (count >= chunkSize)
|
||||
{//满即刷入
|
||||
flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void flush() throws IOException
|
||||
{
|
||||
if (!headed)
|
||||
{
|
||||
output.write(sender.buildChunkedHeader(true));
|
||||
headed = true;
|
||||
}
|
||||
|
||||
writeChunked();
|
||||
}
|
||||
|
||||
/*************************************************************************************/
|
||||
//内部调用的方法
|
||||
/*************************************************************************************/
|
||||
|
||||
/** 重置内容,如前面有写入缓冲,但未提交发现错误 */
|
||||
public void reset()
|
||||
{
|
||||
content.reset();
|
||||
}
|
||||
|
||||
/** 提交流 */
|
||||
public void commit() throws IOException
|
||||
{
|
||||
if (!chunked)
|
||||
{//未分块,写入头和内容
|
||||
output.write(sender.buildChunkedHeader(false));
|
||||
content.writeTo(output);
|
||||
output.flush();
|
||||
}
|
||||
else
|
||||
{//分块,写入最后块和结尾
|
||||
if (content.size() > 0){
|
||||
writeChunked();
|
||||
}
|
||||
|
||||
writeChunkedEnd();
|
||||
}
|
||||
}
|
||||
|
||||
/** 关闭流 */
|
||||
public void finished() throws IOException
|
||||
{
|
||||
if (content != null)
|
||||
{
|
||||
content.close();
|
||||
content = null;
|
||||
}
|
||||
|
||||
output.close();
|
||||
}
|
||||
|
||||
/*************************************************************************************/
|
||||
//整包写入
|
||||
/*************************************************************************************/
|
||||
|
||||
public boolean isChunked()
|
||||
{
|
||||
return chunked;
|
||||
}
|
||||
|
||||
public boolean processGZipCompress()
|
||||
{
|
||||
try
|
||||
{
|
||||
content = Zips.gzip(content);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取写入的长度 */
|
||||
public long getOutputLength()
|
||||
{
|
||||
return output.length();
|
||||
}
|
||||
|
||||
public int getContentLength()
|
||||
{
|
||||
return content.size();
|
||||
}
|
||||
|
||||
/*************************************************************************************/
|
||||
//写入分块数据
|
||||
/*************************************************************************************/
|
||||
|
||||
private void writeChunked() throws IOException
|
||||
{
|
||||
output.write(Ints.toBytesHex(content.size()));
|
||||
output.write(_CRLF_);
|
||||
content.writeTo(output);
|
||||
output.write(_CRLF_);
|
||||
output.flush();
|
||||
|
||||
content.reset();
|
||||
chunked = true;
|
||||
}
|
||||
|
||||
private void writeChunkedEnd() throws IOException
|
||||
{
|
||||
output.write(_0_);
|
||||
output.write(_CRLF_);
|
||||
output.write(_CRLF_);
|
||||
output.flush();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* 记录输出流长度流封装类
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2017-6-14 新建与整理
|
||||
*/
|
||||
public class HttpOutputStreamWrap extends OutputStream
|
||||
{
|
||||
private final HttpConnection conn;
|
||||
private long length;
|
||||
|
||||
public HttpOutputStreamWrap(HttpConnection conn)
|
||||
{
|
||||
this.conn = conn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException
|
||||
{
|
||||
byte[] buf = new byte[]{(byte)b};
|
||||
write(buf, 0, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) throws IOException
|
||||
{
|
||||
conn.write(b, off, len);
|
||||
length += len;
|
||||
}
|
||||
|
||||
public long length()
|
||||
{
|
||||
return length;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,891 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.zhiqim.kernel.util.consts.Int;
|
||||
import org.zhiqim.httpd.validate.Validate;
|
||||
|
||||
/**
|
||||
* HTTP请求接口定义
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2016-7-15 新建与整理
|
||||
*/
|
||||
public interface HttpRequest extends HttpHeader
|
||||
{
|
||||
/** 获取请求编号 */
|
||||
public String getId();
|
||||
|
||||
/** 获取产生时间戳 */
|
||||
public long getTimeMillis();
|
||||
|
||||
/***********************************************************************/
|
||||
//请求状态处理和判断
|
||||
/***********************************************************************/
|
||||
|
||||
/** 设置拦截中 */
|
||||
public void setStepInterceptor();
|
||||
|
||||
/** 设置Action处理中 */
|
||||
public void setStepAction();
|
||||
|
||||
/** 获取当前处理环节 */
|
||||
public int getStep();
|
||||
|
||||
/** 获取当前处理环节描述 */
|
||||
public String getStepDesc();
|
||||
|
||||
/** 是否可读,已读头部之后可读 */
|
||||
public boolean isRead();
|
||||
|
||||
/** 是否可编辑,提交之前可编辑 */
|
||||
public boolean isEditable();
|
||||
|
||||
/** 是否已提交,提交之后不允许再操作request和response */
|
||||
public boolean isCommitted();
|
||||
|
||||
/***********************************************************************/
|
||||
//获取和判断请求行信息,包括协议、方法、版本、URI等
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取协议格式 */
|
||||
public String getScheme();
|
||||
|
||||
/** 获取端口信息 */
|
||||
public int getPort();
|
||||
|
||||
/** 获取URI信息 */
|
||||
public String getRequestURI();
|
||||
|
||||
/** 获取URL信息 */
|
||||
public String getRequestURL();
|
||||
|
||||
/***********************************************************************/
|
||||
//获取和判断请求头部信息
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取消息头名称迭代器 */
|
||||
public Iterator<String> getHeaderNames();
|
||||
|
||||
/** 获取请求头字符串 */
|
||||
public String getHeaderString();
|
||||
|
||||
/** 获取请求头属性 */
|
||||
public String getHeader(String key, String defaultValue);
|
||||
|
||||
/** 获取请求头属性整型值 */
|
||||
public int getHeaderInt(String key);
|
||||
|
||||
/** 获取请求头属性整型值 */
|
||||
public int getHeaderInt(String key, int defaultValue);
|
||||
|
||||
/** 获取请求头属性长整型值 */
|
||||
public long getHeaderLong(String key);
|
||||
|
||||
/** 获取请求头属性长整型值 */
|
||||
public long getHeaderLong(String key, long defaultValue);
|
||||
|
||||
/** 获取组装内容类型 */
|
||||
public String getContentTypeMimeEncoding();
|
||||
|
||||
/** 获取来源地址 */
|
||||
public String getReferer();
|
||||
|
||||
/** 获取知启蒙定义的客户端类型(mobile|www),该值也会设置到request的属性中 */
|
||||
public String getZhiqimClientType();
|
||||
|
||||
/** 是否是异isXMLHttpRequest */
|
||||
public boolean isXMLHttpRequest();
|
||||
|
||||
/** 是否手机端 */
|
||||
public boolean isMobile();
|
||||
|
||||
/** 是否微信 */
|
||||
public boolean isMicroMessenger();
|
||||
|
||||
/** 是否IE浏览器 */
|
||||
public boolean isIE();
|
||||
|
||||
/** 是否是火狐浏览器 */
|
||||
public boolean isFirefox();
|
||||
|
||||
/** 是否是Webkit浏览器 */
|
||||
public boolean isWebkit();
|
||||
|
||||
/** 是否是chrome浏览器 */
|
||||
public boolean isChrome();
|
||||
|
||||
/** 是否是Safari浏览器 */
|
||||
public boolean isSafari();
|
||||
|
||||
/***********************************************************************/
|
||||
//获取监听、服务器、上下文环境、响应、会话相关
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取请求对应的响应对象 */
|
||||
public HttpResponse getResponse();
|
||||
|
||||
/** 获取请求所在的服务 */
|
||||
public HttpServer getServer();
|
||||
|
||||
/** 获取上下文环境路径 */
|
||||
public String getContextPath();
|
||||
|
||||
/** 获取上下文环境名称 */
|
||||
public String getContextName();
|
||||
|
||||
/** 获取上下文环境版本 */
|
||||
public String getContextVersion();
|
||||
|
||||
/** 设置上下文环境属性 */
|
||||
public void setContextAttribute(String key, Object value);
|
||||
|
||||
/** 设置上下文环境属性值(通过类结构) */
|
||||
public <T> void setContextAttribute(Class<T> key, T value);
|
||||
|
||||
/** 获取上下文环境属性值 */
|
||||
public Object getContextAttribute(String key);
|
||||
|
||||
/** 获取上下文环境属性值(通过类结构) */
|
||||
public <T> T getContextAttribute(Class<T> key);
|
||||
|
||||
/** 获取上下文环境属性值 */
|
||||
public Object getContextAttribute(String key, Object defaultValue);
|
||||
|
||||
/** 获取上下文环境属性值字符串 */
|
||||
public String getContextAttributeString(String key);
|
||||
|
||||
/** 获取上下文环境属性值字符串 */
|
||||
public String getContextAttributeString(String key, String defaultValue);
|
||||
|
||||
/** 获取上下文环境属性值整型 */
|
||||
public int getContextAttributeInt(String key);
|
||||
|
||||
/** 获取上下文环境属性值整型 */
|
||||
public int getContextAttributeInt(String key, int defaultValue);
|
||||
|
||||
/** 获取上下文环境属性值长整型 */
|
||||
public long getContextAttributeLong(String key);
|
||||
|
||||
/** 获取上下文环境属性值长整型 */
|
||||
public long getContextAttributeLong(String key, long defaultValue);
|
||||
|
||||
/** 获取上下文环境属性值布尔型 */
|
||||
public boolean getContextAttributeBoolean(String key, boolean defaultValue);
|
||||
|
||||
/** 判断上下文环境是否有属性值 */
|
||||
public boolean hasContextAttribute(String key);
|
||||
|
||||
/** 获取当前WEB目录根目录,注意没有/结尾 */
|
||||
public String getResourcePath();
|
||||
|
||||
/** 获取上下文环境下绝对路径转为根环境下的绝对路径,如contextPath=/doc,path=/index.htm,得到/doc/index.htm */
|
||||
public String getRootPath(String path);
|
||||
|
||||
/** 获取当前WEB目录路径转换成绝对路径 */
|
||||
public String getRealPath(String path);
|
||||
|
||||
/** 获取SSL证书 */
|
||||
public X509Certificate[] getCertificates();
|
||||
|
||||
/***********************************************************************/
|
||||
//设置和获取Session中属性
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取请求用户名 */
|
||||
public String getRequestName();
|
||||
|
||||
/** 设置请求用户名 */
|
||||
public void setRequestName(String name);
|
||||
|
||||
/** 获取会话编号 */
|
||||
public String getSessionId();
|
||||
|
||||
/** 获取请求对应的会话环境 */
|
||||
public HttpSession getSession();
|
||||
|
||||
/** 删除会话 */
|
||||
public void invalidateSession();
|
||||
|
||||
/** 判断是否绑定了登录用户 */
|
||||
public boolean hasSessionUser();
|
||||
|
||||
/** 绑定会话登录用户 */
|
||||
public void bindSessionUser(HttpSessionUser sessionUser);
|
||||
|
||||
/** 解除绑定会话登录用户 */
|
||||
public void unbindSessionUser();
|
||||
|
||||
/** 判断是否绑定了登录用户,且指定的会话用户类(HttpSessionUser子类) */
|
||||
public <T extends HttpSessionUser> boolean hasSessionUser(Class<T> clazz);
|
||||
|
||||
/** 获取会话用户信息,且指定的会话用户类(HttpSessionUser子类) */
|
||||
public <T extends HttpSessionUser> T getSessionUser(Class<T> clazz);
|
||||
|
||||
/** 获取会话默认的用户信息 */
|
||||
public HttpSessionUser getSessionUser();
|
||||
|
||||
/** 获取会话默认的登录名 */
|
||||
public String getSessionName();
|
||||
|
||||
/** 设置会话属性 */
|
||||
public void setSessionAttribute(String name, Object value);
|
||||
|
||||
/** 获取会话属性值 */
|
||||
public Object getSessionAttribute(String name);
|
||||
|
||||
/** 获取会话属性值 */
|
||||
public Object getSessionAttribute(String name, Object defaultValue);
|
||||
|
||||
/** 获取会话属性值字符串 */
|
||||
public String getSessionAttributeString(String name);
|
||||
|
||||
/** 获取会话属性值字符串 */
|
||||
public String getSessionAttributeString(String name, String defaultValue);
|
||||
|
||||
/** 获取会话属性值整型 */
|
||||
public int getSessionAttributeInt(String name);
|
||||
|
||||
/** 获取会话属性值整型 */
|
||||
public int getSessionAttributeInt(String name, int defaultValue);
|
||||
|
||||
/** 获取会话属性值长整型 */
|
||||
public long getSessionAttributeLong(String name);
|
||||
|
||||
/** 获取会话属性值长整型 */
|
||||
public long getSessionAttributeLong(String name, long defaultValue);
|
||||
|
||||
/** 判断会话是否有属性值 */
|
||||
public boolean hasSessionAttribute(String name);
|
||||
|
||||
/***********************************************************************/
|
||||
//获取Cookie数据或数组
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取指定名称的Cookie */
|
||||
public String getCookie(String name);
|
||||
|
||||
/** 获取Cookie,如果没有值或值为空字符串返回缺省值 */
|
||||
public String getCookie(String name, String defaultValue);
|
||||
|
||||
/** 获取请求中Cookie数组 */
|
||||
public HttpCookie[] getCookies();
|
||||
|
||||
/** 删除请求中的Cookie值 */
|
||||
public void removeCookie(String name);
|
||||
|
||||
/** 增加Cookie到响应中 */
|
||||
public void addCookieToResponse(String name, String value);
|
||||
|
||||
/** 增加Cookie到响应中 */
|
||||
public void addCookieToResponse(String name, String value, int seconds);
|
||||
|
||||
/** 增加Cookie到响应中 */
|
||||
public void addCookieToResponse(HttpCookie cookie);
|
||||
|
||||
/** 删除Cookie到响应中 */
|
||||
public void removeCookieToResponse(String name);
|
||||
|
||||
/***********************************************************************/
|
||||
//获取请求中URL匹配的参数
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取通配符参数列表 */
|
||||
public List<String> getParameterMatch();
|
||||
|
||||
/**
|
||||
* 获取通配符参数值
|
||||
*
|
||||
* @param index 参数匹配位置
|
||||
* @return 有过滤的参数值
|
||||
*/
|
||||
public String getParameterMatch(int index);
|
||||
|
||||
/**
|
||||
* 获取通配符参数值
|
||||
*
|
||||
* @param index 参数匹配位置
|
||||
* @return 有过滤的参数值
|
||||
*/
|
||||
public long getParameterMatchLong(int index);
|
||||
|
||||
/**
|
||||
* 获取通配符参数值
|
||||
*
|
||||
* @param index 参数匹配位置
|
||||
* @return 有过滤的参数值
|
||||
*/
|
||||
public int getParameterMatchInt(int index);
|
||||
|
||||
/***********************************************************************/
|
||||
//获取请求中URL和Content中的数据,包括URL和Content中的数据
|
||||
/***********************************************************************/
|
||||
|
||||
/**
|
||||
* 获取参数哈唏表(未安全过滤),先填入url中参数表,再用content参数表覆盖,得到全部参数表
|
||||
*
|
||||
* @return 得到全部参数表
|
||||
*/
|
||||
public HashMap<String, String> getParameterMap();
|
||||
|
||||
/** 判断是否有参数 */
|
||||
public boolean hasParameter(String name);
|
||||
|
||||
/**
|
||||
* 获取参数值并安全过滤,优先检查content中是否存在,如果不存在才检查url中
|
||||
*
|
||||
* @param name 参数名
|
||||
* @return 有过滤的参数值
|
||||
*/
|
||||
public String getParameter(String name);
|
||||
|
||||
/**
|
||||
* 获取动态参数对象信息
|
||||
*
|
||||
* @param clazz 类结构
|
||||
* @return 返回赋值后的对象
|
||||
* @throws 异常需要捕捉
|
||||
*/
|
||||
public <T> T getParameter(Class<T> clazz) throws IllegalAccessException;
|
||||
|
||||
/**
|
||||
* 获取参数值(未过滤),优先检查content中是否存在,如果不存在才检查url中
|
||||
*
|
||||
* @param name 参数名
|
||||
* @return 有过滤的参数值
|
||||
*/
|
||||
public String getParameterNoFilter(String name);
|
||||
|
||||
/**
|
||||
* 获取参数值并安全过滤,优先检查content中是否存在,如果不存在才检查url中,都不存在或值为空白返回缺省值
|
||||
*
|
||||
* @param name 参数名
|
||||
* @param defaultValue 不存在或为空时的缺省值
|
||||
* @return 有过滤的参数值
|
||||
*/
|
||||
public String getParameter(String name, String defaultValue);
|
||||
|
||||
/**
|
||||
* 获取参数值(未过滤),优先检查content中是否存在,如果不存在才检查url中,都不存在或值为空白返回缺省值
|
||||
*
|
||||
* @param name 参数名
|
||||
* @param defaultValue 不存在或为空时的缺省值
|
||||
* @return 有过滤的参数值
|
||||
*/
|
||||
public String getParameterNoFilter(String name, String defaultValue);
|
||||
|
||||
/**
|
||||
* 获取参数整型,非整型返回-1的值
|
||||
*
|
||||
* @param name 参数名
|
||||
* @return 整数值
|
||||
*/
|
||||
public int getParameterInt(String name);
|
||||
|
||||
/**
|
||||
* 获取参数整型,非整型返回缺省值
|
||||
*
|
||||
* @param name 参数名
|
||||
* @param defaultValue 缺省值
|
||||
* @return 整数值
|
||||
*/
|
||||
public int getParameterInt(String name, int defaultValue);
|
||||
|
||||
/**
|
||||
* 获取参数长整型,非整型返回-1的值
|
||||
*
|
||||
* @param name 参数名
|
||||
* @return 长整型
|
||||
*/
|
||||
public long getParameterLong(String name);
|
||||
|
||||
/**
|
||||
* 获取参数长整型,非整型返回-1的值
|
||||
*
|
||||
* @param name 参数名
|
||||
* @param defaultValue 缺省值
|
||||
* @return 长整型
|
||||
*/
|
||||
public long getParameterLong(String name, long defaultValue);
|
||||
|
||||
/**
|
||||
* 获取参数布尔型,非布尔型返回false的值
|
||||
*
|
||||
* @param name 参数名
|
||||
* @return 布尔型
|
||||
*/
|
||||
public boolean getParameterBoolean(String name);
|
||||
|
||||
/**
|
||||
* 获取参数布尔型,非布尔型返回false的值
|
||||
*
|
||||
* @param name 参数名
|
||||
* @param defaultValue 缺省值
|
||||
* @return 布尔型
|
||||
*/
|
||||
public boolean getParameterBoolean(String name, boolean defaultValue);
|
||||
|
||||
/**
|
||||
* 获取两位小数的金额值,格式不对返回-1
|
||||
*
|
||||
* @param name 参数名
|
||||
* @return 金额值,如果从请求中获取的格式不对,则返回-1
|
||||
*/
|
||||
public int getParameterAmount2R(String name);
|
||||
|
||||
/**
|
||||
* 获取两位小数的金额值
|
||||
*
|
||||
* @param name 参数名
|
||||
* @param defaultValue 缺省值
|
||||
* @return 金额值,如果从请求中获取的格式不对,则返回缺省值
|
||||
*/
|
||||
public int getParameterAmount2R(String name, int defaultValue);
|
||||
|
||||
/**
|
||||
* 获取两位小数的金额值长整型,格式不对返回-1
|
||||
*
|
||||
* @param name 参数名
|
||||
* @param defaultValue 缺省值
|
||||
* @return 金额值,如果从请求中获取的格式不对,则返回-1
|
||||
*/
|
||||
public long getParameterAmount2RLong(String name);
|
||||
|
||||
/**
|
||||
* 获取两位小数的金额值长整型
|
||||
*
|
||||
* @param name 参数名
|
||||
* @param defaultValue 缺省值
|
||||
* @return 金额值,如果从请求中获取的格式不对,则返回缺省值
|
||||
*/
|
||||
public long getParameterAmount2R(String name, long defaultValue);
|
||||
|
||||
/**
|
||||
* 获取参数值并安全过滤,并转化为数组(逗号格式),优先检查content中是否存在,如果不存在才检查url中
|
||||
*
|
||||
* @param name 参数名
|
||||
* @return 有过滤后的逗号格式数组值
|
||||
*/
|
||||
public String[] getParameterValues(String name);
|
||||
|
||||
/**
|
||||
* 获取参数值(未过滤),并转化为数组(逗号格式),优先检查content中是否存在,如果不存在才检查url中
|
||||
*
|
||||
* @param name 参数名
|
||||
* @return 有过滤后的逗号格式数组值
|
||||
*/
|
||||
public String[] getParameterValuesNoFilter(String name);
|
||||
|
||||
/***********************************************************************/
|
||||
//获取请求中URL中的数据
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取URL参数哈唏表(值未过滤) */
|
||||
public HashMap<String,String> getParameterMapOnURL();
|
||||
|
||||
/** 判断是否有URL参数 */
|
||||
public boolean hasParameterOnURL(String name);
|
||||
|
||||
/** 获取URL参数值,并安全过滤 */
|
||||
public String getParameterOnURL(String name);
|
||||
|
||||
/** 获取URL参数值,并安全过滤 */
|
||||
public String getParameterOnURL(String name, String defaultValue);
|
||||
|
||||
/** 获取URL参数值(未过滤) */
|
||||
public String getParameterNoFilterOnURL(String name);
|
||||
|
||||
/** 获取URL参数值(未过滤) */
|
||||
public String getParameterNoFilterOnURL(String name, String defaultValue);
|
||||
|
||||
/** 获取URL参数整型,非整型返回-1的值 */
|
||||
public int getParameterIntOnURL(String name);
|
||||
|
||||
/** 获取URL参数整型,非整型返回缺省值 */
|
||||
public int getParameterIntOnURL(String name, int defaultValue);
|
||||
|
||||
/** 获取URL参数长整型,非整型返回-1的值 */
|
||||
public long getParameterLongOnURL(String name);
|
||||
|
||||
/** 获取URL参数长整型,非整型返回-1的值 */
|
||||
public long getParameterLongOnURL(String name, long defaultValue);
|
||||
|
||||
/** 获取两位小数的金额值 */
|
||||
public int getParameterAmount2ROnURL(String name, int defaultValue);
|
||||
|
||||
/** 获取两位小数的金额值长整型 */
|
||||
public long getParameterAmount2ROnURL(String name, long defaultValue);
|
||||
|
||||
/** 获取URL参数值数组,并安全过滤 */
|
||||
public String[] getParameterValuesOnURL(String name);
|
||||
|
||||
/***********************************************************************/
|
||||
//获取请求中Content中的数据
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取内容输入流 */
|
||||
public InputStream getInputStream();
|
||||
|
||||
/** 获取内容输入流字符串 */
|
||||
public String getInputStreamString();
|
||||
|
||||
/** 获取内容参数哈唏表(值未过滤) */
|
||||
public HashMap<String,String> getParameterMapOnCNT();
|
||||
|
||||
/** 判断是否有内容参数 */
|
||||
public boolean hasParameterOnCNT(String name);
|
||||
|
||||
/** 获取内容参数值,并安全过滤 */
|
||||
public String getParameterOnCNT(String name);
|
||||
|
||||
/** 获取内容参数值,并安全过滤 */
|
||||
public String getParameterOnCNT(String name, String defaultValue);
|
||||
|
||||
/** 获取内容参数值(未过滤) */
|
||||
public String getParameterNoFileterOnCNT(String name);
|
||||
|
||||
/** 获取内容参数值(未过滤) */
|
||||
public String getParameterNoFileterOnCNT(String name, String defaultValue);
|
||||
|
||||
/** 获取内容参数整型,非整型返回-1的值 */
|
||||
public int getParameterIntOnCNT(String name);
|
||||
|
||||
/** 获取内容参数整型,非整型返回缺省值 */
|
||||
public int getParameterIntOnCNT(String name, int defaultValue);
|
||||
|
||||
/** 获取内容参数长整型,非整型返回-1的值 */
|
||||
public long getParameterLongOnCNT(String name);
|
||||
|
||||
/** 获取内容参数长整型,非整型返回-1的值 */
|
||||
public long getParameterLongOnCNT(String name, long defaultValue);
|
||||
|
||||
/** 获取内容参数两位小数的金额值 */
|
||||
public int getParameterAmount2ROnCNT(String name, int defaultValue);
|
||||
|
||||
/** 获取内容参数两位小数的金额值长整型 */
|
||||
public long getParameterAmount2ROnCNT(String name, long defaultValue);
|
||||
|
||||
/** 获取内容参数值数组 */
|
||||
public String[] getParameterValuesOnCNT(String name);
|
||||
|
||||
/** 设置参数值到URL表中 */
|
||||
public void setParameterOnURL(String name, Object value);
|
||||
|
||||
/** 设置参数值到CNT表中 */
|
||||
public void setParameterOnCNT(String name, Object value);
|
||||
|
||||
/***********************************************************************/
|
||||
//设置和获取请求中属性
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取属性列表 */
|
||||
public Map<String, Object> getAttributeMap();
|
||||
|
||||
/** 获取属性值 */
|
||||
public Object getAttribute(String name);
|
||||
|
||||
/** 获取属性值,如果无该属性则返回缺省值 */
|
||||
public Object getAttribute(String name, Object defaultValue);
|
||||
|
||||
/** 获取属性值字符串 */
|
||||
public String getAttributeString(String name);
|
||||
|
||||
/** 获取属性值字符串,如果无该属性则返回缺省值 */
|
||||
public String getAttributeString(String name, String defaultValue);
|
||||
|
||||
/** 获取属性值整型 */
|
||||
public int getAttributeInt(String name);
|
||||
|
||||
/** 获取属性值整型,如果无该属性则返回缺省值 */
|
||||
public int getAttributeInt(String name, int defaultValue);
|
||||
|
||||
/** 获取属性值整型 */
|
||||
public long getAttributeLong(String name);
|
||||
|
||||
/** 获取属性值整型,如果无该属性则返回缺省值 */
|
||||
public long getAttributeLong(String name, int defaultValue);
|
||||
|
||||
/** 判断属性是否存在 */
|
||||
public boolean hasAttribute(String name);
|
||||
|
||||
/** 设置属性 */
|
||||
public void setAttribute(String name, Object value);
|
||||
|
||||
/***********************************************************************/
|
||||
//获取请求/会话/上下文环境中嵌套属性,有则返回
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取属性值 */
|
||||
public Object getNestAttribute(String name);
|
||||
|
||||
/** 获取属性值,如果无该属性则返回缺省值 */
|
||||
public Object getNestAttribute(String name, Object defaultValue);
|
||||
|
||||
/** 获取属性值字符串 */
|
||||
public String getNestAttributeString(String name);
|
||||
|
||||
/** 获取属性值字符串,如果无该属性则返回缺省值 */
|
||||
public String getNestAttributeString(String name, String defaultValue);
|
||||
|
||||
/** 获取属性值整型 */
|
||||
public int getNestAttributeInt(String name);
|
||||
|
||||
/** 获取属性值整型,如果无该属性则返回缺省值 */
|
||||
public int getNestAttributeInt(String name, int defaultValue);
|
||||
|
||||
/** 获取属性值整型 */
|
||||
public long getNestAttributeLong(String name);
|
||||
|
||||
/** 获取属性值整型,如果无该属性则返回缺省值 */
|
||||
public long getNestAttributeLong(String name, int defaultValue);
|
||||
|
||||
/** 判断属性是否存在 */
|
||||
public boolean hasNestAttribute(String name);
|
||||
|
||||
/***********************************************************************/
|
||||
//内部重定向请求和上下文环境下绝对路径
|
||||
/***********************************************************************/
|
||||
|
||||
/**
|
||||
* 内部重定向请求,支持从一个Action内部转到新的Action处理
|
||||
*
|
||||
* @param pathInContext 上下文内部路径,即对应的新Action的配置路径
|
||||
* @throws IOException IO异常
|
||||
* @throws HttpException HTTP异常
|
||||
*/
|
||||
public void forwardTo(String pathInContext) throws HttpException, IOException;
|
||||
|
||||
/** 是否已标志为已内部重定向 */
|
||||
public boolean hasForward();
|
||||
|
||||
/***********************************************************************/
|
||||
//以下为响应相关配置
|
||||
/***********************************************************************/
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
//从请求中设置属性到响应中
|
||||
/***********************************************************************/
|
||||
|
||||
/**
|
||||
* 设置响应配置信息
|
||||
*
|
||||
* @param view 转向到视图页
|
||||
* @param include 转向到视图页的嵌套地址
|
||||
* @param forward 转向到新的路径
|
||||
* @param redirect 重定向到新的路径
|
||||
* @param method 执行类的方法
|
||||
* @param alert 执行后的警告信息
|
||||
*/
|
||||
public void setResponseConfig(String view, String include, String forward, String redirect, String method, String alert);
|
||||
|
||||
/** 设置响应私用缓存 */
|
||||
public void setResponsePrivateCache();
|
||||
|
||||
/** 设置响应头不缓存 */
|
||||
public void setResponseNoCache();
|
||||
|
||||
/** 设置响应为UTF8编码*/
|
||||
public void setResponseEncodingUTF8();
|
||||
|
||||
/***********************************************************************/
|
||||
//设置响应的配置信息
|
||||
/***********************************************************************/
|
||||
|
||||
/** 修改为是否转向 */
|
||||
public void setReturn(boolean isReturn);
|
||||
|
||||
/** 设置成功失败信息 */
|
||||
public void setAlertMsg(String errorMsg);
|
||||
|
||||
/** 修改视图页和嵌套地址,和转向页互斥 */
|
||||
public void setView(String view, String include);
|
||||
|
||||
/** 修改为内部转向地址 */
|
||||
public void setForward(String forwardTo);
|
||||
|
||||
/** 修改重定向,状态码为602 */
|
||||
public void setRedirect(String redirect);
|
||||
|
||||
/** 修改重定向,和视图页互斥,但不改变responseStatus值 */
|
||||
public void setRedirectInner(String redirect);
|
||||
|
||||
/** 修改父页重定向,状态码为601 */
|
||||
public void setRedirectParent(String redirect);
|
||||
|
||||
/** 修改顶页重定向 ,状态码为603*/
|
||||
public void setRedirectTop(String redirect);
|
||||
|
||||
/** 修改重定向前提示错误,状态码为602 */
|
||||
public void setRedirect(String redirect, String error);
|
||||
|
||||
/** 修改父页重定向前提示错误,状态码为601 */
|
||||
public void setRedirectParent(String redirect, String error);
|
||||
|
||||
/** 修改顶页重定向前提示错误,状态码为603 */
|
||||
public void setRedirectTop(String redirect, String error);
|
||||
|
||||
/***********************************************************************/
|
||||
//从请求中设置响应状态和文本属性
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取响应属性码 */
|
||||
public int getResponseStatus();
|
||||
|
||||
/** 获取响应属性文本 */
|
||||
public String getResponseText();
|
||||
|
||||
/** 判断响应属性是不是成功 */
|
||||
public boolean isResponseSuccess();
|
||||
|
||||
/** 判断响应属性是不是重定向 */
|
||||
public boolean isResponseRedirect();
|
||||
|
||||
/** 设置响应结果属性,指定状态码但不能小于0,不能填70-699之间已知的状态码 */
|
||||
public void setResponseResult(int responseStatus, String responseText);
|
||||
|
||||
/** 设置响应结果属性,指定状态码但不能小于0,不能填70-699之间已知的状态码 */
|
||||
public void setResponseResult(Int result);
|
||||
|
||||
/** 设置响应结果属性,状态码为0,表示成功 */
|
||||
public void setResponseResult(String responseText);
|
||||
|
||||
/** 设置响应结果属性,状态码为699,表示通用的失败 */
|
||||
public void setResponseError(String responseText);
|
||||
|
||||
/**********************************************/
|
||||
//加上四个常用特性方法,用于运行时修改设置
|
||||
/**********************************************/
|
||||
|
||||
/** 增加一个返回上一页快捷方式 */
|
||||
public void returnHistory();
|
||||
|
||||
/** 增加一个错误返回上一页并提示错误的快捷方式 */
|
||||
public void returnHistory(String errorMsg);
|
||||
|
||||
/** 增加一个弹出窗口时关闭快捷方式 */
|
||||
public void returnCloseWindow();
|
||||
|
||||
/** 增加一个弹出窗口时关闭并提示错误的快捷方式 */
|
||||
public void returnCloseWindow(String errorMsg);
|
||||
|
||||
/** 增加一个弹出对话框时关闭快捷方式 */
|
||||
public void returnCloseDialog();
|
||||
|
||||
/** 增加一个弹出对话框时关闭并提示错误的快捷方式 */
|
||||
public void returnCloseDialog(String errorMsg);
|
||||
|
||||
/** 增加参数 */
|
||||
public void addParam(String key, Object value);
|
||||
|
||||
/*******************************************************************************/
|
||||
//转向控制字段相关属性
|
||||
/*******************************************************************************/
|
||||
|
||||
/**
|
||||
* 检查是否转向,两种情况<br><br>
|
||||
*
|
||||
* 1、当设置成强制不转向时,即不转向<br>
|
||||
* 2、当为转向时,检查视图页和转向页是否存在,存在一个即转向,否则不转向<br>
|
||||
*/
|
||||
public boolean isReturn();
|
||||
|
||||
/** 获取Action在execute中转向的方法名 */
|
||||
public String getExecuteMethod();
|
||||
|
||||
/** 获取转向定制的提示信息 */
|
||||
public String getAlertMsg();
|
||||
|
||||
/** 获取视图信息 */
|
||||
public String getView();
|
||||
|
||||
/** 获取视图信息嵌套地址 */
|
||||
public String getInclude();
|
||||
|
||||
/** 获取内转向地址 */
|
||||
public String getForward(String encoding);
|
||||
|
||||
/** 获取重定向地址 */
|
||||
public String getRedirect(String encoding);
|
||||
|
||||
/** 获取重定向内部定义的地址 */
|
||||
public String getRedirectInner();
|
||||
|
||||
/***********************************************/
|
||||
//以下判断是否强制要求转向
|
||||
/***********************************************/
|
||||
|
||||
/**
|
||||
* 是否强制转向
|
||||
*
|
||||
* 1.如果有失败提示或成功提示,需强制转向
|
||||
* 2.由业务指定返回上一页或关闭,需强制转向
|
||||
*/
|
||||
public boolean isForceReturn();
|
||||
|
||||
/**
|
||||
* 获取强制转向类型
|
||||
*
|
||||
* 1.返回上一页
|
||||
* 2.关闭当前窗口
|
||||
* 3.关闭对话框
|
||||
* 4.调用Javascript
|
||||
* 0.表示正常连接
|
||||
* @return int 类型
|
||||
*/
|
||||
public int getForceReturnType();
|
||||
|
||||
/*******************************************************************************/
|
||||
//验证相关属性
|
||||
/*******************************************************************************/
|
||||
|
||||
/** 获取验证列表 */
|
||||
public List<Validate> getValidateList();
|
||||
|
||||
/** 获取验证脚本 */
|
||||
public String getValidateScript();
|
||||
|
||||
/** 获取验证提交脚本 */
|
||||
public String getValidateSubmitScript();
|
||||
|
||||
/** 增加验证信息 */
|
||||
public void addValidate(Validate validate);
|
||||
|
||||
/** 清除所有的验证信息 */
|
||||
public void clearValidate();
|
||||
|
||||
/** 检查验证信息 */
|
||||
public boolean chkValidate();
|
||||
|
||||
/** 设置验证确认信息 */
|
||||
public void setValidateConfirm(String confirm);
|
||||
|
||||
/** 设置验证提交时是否按钮变灰,默认变灰 */
|
||||
public void setValidateGray(boolean isGray);
|
||||
}
|
||||
Diff onderdrukt omdat het te groot bestand
Laad Diff
@@ -0,0 +1,477 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.zhiqim.kernel.util.Strings;
|
||||
import org.zhiqim.kernel.util.Urls;
|
||||
import org.zhiqim.kernel.util.Validates;
|
||||
import org.zhiqim.kernel.util.consts.Int;
|
||||
|
||||
/**
|
||||
* HTTP请求响应抽象类,把响应相关的处理的放在该类中
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2016-7-15 新建与整理
|
||||
*/
|
||||
public abstract class HttpRequestResponse extends HttpRequestValidate
|
||||
{
|
||||
private boolean isReturn; //是否转向,=false时[tempalte|forward|redirect]无效
|
||||
|
||||
//用于在请求中设置响应属性
|
||||
private int responseStatus; //601-603表示重定向
|
||||
|
||||
//三项为Action配置的转向控制字段
|
||||
private String forward; //转向到新的path
|
||||
private String redirect; //重定向到新path
|
||||
private String view; //加载视图信息
|
||||
private String include; //加载视图嵌套信息
|
||||
private String executeMethod; //内部通过execute转向到该方法
|
||||
private String alertMsg; //提示信息
|
||||
|
||||
//一项为转向时的可选配置字段
|
||||
private List<String[]> paramList; //重定向参数列表
|
||||
|
||||
/**
|
||||
* 设置响应配置信息
|
||||
*
|
||||
* @param view 转向到视图页
|
||||
* @param include 转向到视图页的嵌套地址
|
||||
* @param forward 转向到新的路径
|
||||
* @param redirect 重定向到新的路径
|
||||
* @param method 执行类的方法
|
||||
* @param alert 执行后的警告信息
|
||||
*/
|
||||
public void setResponseConfig(String view, String include, String forward, String redirect, String method, String alert)
|
||||
{
|
||||
this.isReturn = !Validates.isEmptyBlank(view) || !Validates.isEmptyBlank(forward) || !Validates.isEmptyBlank(redirect);
|
||||
|
||||
this.view = view;
|
||||
this.include = include;
|
||||
this.forward = forward;
|
||||
this.redirect = redirect;
|
||||
|
||||
this.executeMethod = method;
|
||||
this.alertMsg = alert;
|
||||
}
|
||||
|
||||
/**********************************************/
|
||||
//加上标准SET方法,用于运行时修改设置
|
||||
/**********************************************/
|
||||
|
||||
/** 修改为是否转向 */
|
||||
public void setReturn(boolean isReturn)
|
||||
{
|
||||
this.isReturn = isReturn;
|
||||
}
|
||||
|
||||
/** 修改视图页和嵌套地址,和转向页互斥 */
|
||||
public void setView(String view, String include)
|
||||
{
|
||||
this.responseStatus = 0;
|
||||
|
||||
this.view = view;
|
||||
this.include = include;
|
||||
this.forward = null;
|
||||
this.redirect = null;
|
||||
this.isReturn = true;
|
||||
}
|
||||
|
||||
/** 修改为是否内部转向 */
|
||||
public void setForward(String forwardTo)
|
||||
{
|
||||
this.responseStatus = 0;
|
||||
|
||||
this.forward = forwardTo;
|
||||
this.view = null;
|
||||
this.redirect = null;
|
||||
this.isReturn = true;
|
||||
}
|
||||
|
||||
/** 修改重定向,和视图页互斥 */
|
||||
public void setRedirect(String redirect)
|
||||
{
|
||||
this.responseStatus = _602_REDIRECT_;
|
||||
|
||||
setRedirectInner(redirect);
|
||||
}
|
||||
|
||||
/** 修改重定向,和视图页互斥,但不改变responseStatus值 */
|
||||
public void setRedirectInner(String redirect)
|
||||
{
|
||||
this.redirect = redirect;
|
||||
this.view = null;
|
||||
this.forward = null;
|
||||
this.isReturn = true;
|
||||
}
|
||||
|
||||
/** 增加参数,内转向和重定向时有效 */
|
||||
public void addParam(String key, Object value)
|
||||
{
|
||||
if (value == null)
|
||||
value = "";
|
||||
|
||||
if (paramList == null)
|
||||
paramList = new ArrayList<>(2);
|
||||
|
||||
paramList.add(new String[]{key, String.valueOf(value)});
|
||||
}
|
||||
|
||||
/** 设置警告信息 */
|
||||
public void setAlertMsg(String alert)
|
||||
{
|
||||
this.alertMsg = alert;
|
||||
}
|
||||
|
||||
/*******************************************************************************/
|
||||
//转向控制字段相关属性
|
||||
/*******************************************************************************/
|
||||
|
||||
/** 获取Action在execute中转向的方法名 */
|
||||
public String getExecuteMethod()
|
||||
{
|
||||
return executeMethod;
|
||||
}
|
||||
|
||||
/** 获取转向定制的提示信息 */
|
||||
public String getAlertMsg()
|
||||
{
|
||||
return alertMsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否转向,两种情况<br><br>
|
||||
*
|
||||
* 1、当设置成强制不转向时,即不转向<br>
|
||||
* 2、当为转向时,检查视图页和转向页是否存在,存在一个即转向,否则不转向<br>
|
||||
*/
|
||||
public boolean isReturn()
|
||||
{
|
||||
return isReturn?(Validates.isNotEmpty(view) || Validates.isNotEmpty(forward) || Validates.isNotEmpty(redirect)):false;
|
||||
}
|
||||
|
||||
/** 获取视图信息 */
|
||||
public String getView()
|
||||
{
|
||||
return view;
|
||||
}
|
||||
|
||||
/** 获取视图信息嵌套信息 */
|
||||
public String getInclude()
|
||||
{
|
||||
return include;
|
||||
}
|
||||
|
||||
/** 获取内转向地址 */
|
||||
public String getForward(String encoding)
|
||||
{
|
||||
if (Validates.isEmpty(paramList))
|
||||
return forward;
|
||||
|
||||
//加参数
|
||||
for (String[] param : paramList)
|
||||
{
|
||||
String value = Urls.encode(param[1], encoding);
|
||||
forward = Urls.add(forward, param[0], value);
|
||||
}
|
||||
return forward;
|
||||
}
|
||||
|
||||
/** 获取重定向内部定义的地址 */
|
||||
public String getRedirectInner()
|
||||
{
|
||||
return redirect;
|
||||
}
|
||||
|
||||
/** 获取重定向地址 */
|
||||
public String getRedirect(String encoding)
|
||||
{
|
||||
if (redirect == null)
|
||||
return redirect;
|
||||
|
||||
if (_REDIRECT_HISTORY_.equals(redirect))
|
||||
return redirect;
|
||||
|
||||
if (_REDIRECT_CLOSE_WINDOW_.equals(redirect))
|
||||
return redirect;
|
||||
|
||||
if (_REDIRECT_CLOSE_DIALOG_.equals(redirect))
|
||||
return redirect;
|
||||
|
||||
if (Strings.startsWith(redirect, "javascript:"))
|
||||
return redirect;
|
||||
|
||||
if (Validates.isEmpty(paramList))
|
||||
return redirect;
|
||||
|
||||
//加参数
|
||||
for (String[] param : paramList)
|
||||
{
|
||||
String value = Urls.encode(param[1], encoding);
|
||||
redirect = Urls.add(redirect, param[0], value);
|
||||
}
|
||||
return redirect;
|
||||
}
|
||||
|
||||
/**********************************************/
|
||||
//加上四个常用特性方法,用于运行时修改设置
|
||||
/**********************************************/
|
||||
|
||||
/** 增加一个返回上一页快捷方式 */
|
||||
public void returnHistory()
|
||||
{
|
||||
setRedirect(_REDIRECT_HISTORY_);
|
||||
}
|
||||
|
||||
/** 增加一个错误返回上一页并提示错误的快捷方式 */
|
||||
public void returnHistory(String errorMsg)
|
||||
{
|
||||
setRedirect(_REDIRECT_HISTORY_);
|
||||
setAlertMsg(errorMsg);
|
||||
}
|
||||
|
||||
/** 增加一个弹出窗口时关闭快捷方式 */
|
||||
public void returnCloseWindow()
|
||||
{
|
||||
setRedirect(_REDIRECT_CLOSE_WINDOW_);
|
||||
}
|
||||
|
||||
/** 增加一个弹出窗口时关闭并提示错误的快捷方式 */
|
||||
public void returnCloseWindow(String errorMsg)
|
||||
{
|
||||
setRedirect(_REDIRECT_CLOSE_WINDOW_);
|
||||
setAlertMsg(errorMsg);
|
||||
}
|
||||
|
||||
/** 增加一个弹出对话框时关闭快捷方式 */
|
||||
public void returnCloseDialog()
|
||||
{
|
||||
setRedirect(_REDIRECT_CLOSE_DIALOG_);
|
||||
}
|
||||
|
||||
/** 增加一个弹出对话框时关闭并提示错误的快捷方式 */
|
||||
public void returnCloseDialog(String errorMsg)
|
||||
{
|
||||
setRedirect(_REDIRECT_CLOSE_DIALOG_);
|
||||
setAlertMsg(errorMsg);
|
||||
}
|
||||
|
||||
/***********************************************/
|
||||
//以下判断是否强制要求转向(通过JS转向的)
|
||||
/***********************************************/
|
||||
|
||||
/**
|
||||
* 是否强制转向
|
||||
*
|
||||
* 1.如果有失败提示或成功提示,需强制转向
|
||||
* 2.由业务指定返回上一页或关闭,需强制转向
|
||||
*/
|
||||
public boolean isForceReturn()
|
||||
{
|
||||
//要提示信息要求alert
|
||||
if (Validates.isNotEmpty(alertMsg))
|
||||
return true;
|
||||
|
||||
//当要求返回上一页、关闭当前页和关闭当前对话框时需强制转向
|
||||
if (_REDIRECT_HISTORY_.equals(redirect) || _REDIRECT_CLOSE_WINDOW_.equals(redirect) || _REDIRECT_CLOSE_DIALOG_.equals(redirect))
|
||||
return true;
|
||||
|
||||
//当要求执行一段javascript代码时
|
||||
if (Strings.startsWith(redirect, "javascript:"))
|
||||
return true;
|
||||
|
||||
//parent.location和top.location两种必须强制转向
|
||||
if (responseStatus == _601_REDIRECT_PARENT_ || responseStatus == _603_REDIRECT_TOP_)
|
||||
return true;
|
||||
|
||||
//在iframe中的提交,要强制转向
|
||||
if (getParameterBoolean(_PARAM_CALL_FRAME_))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取强制转向类型
|
||||
*
|
||||
* 1.返回上一页
|
||||
* 2.关闭当前窗口
|
||||
* 3.关闭对话框
|
||||
* 4.调用Javascript
|
||||
* 0.表示正常连接
|
||||
* @return int 类型
|
||||
*/
|
||||
public int getForceReturnType()
|
||||
{
|
||||
//当要求返回上一页、关闭当前页和关闭当前对话框时需强制转向
|
||||
if (redirect == null)
|
||||
return -1;
|
||||
if (_REDIRECT_HISTORY_.equals(redirect))
|
||||
return 1;
|
||||
else if(_REDIRECT_CLOSE_WINDOW_.equals(redirect))
|
||||
return 2;
|
||||
else if(_REDIRECT_CLOSE_DIALOG_.equals(redirect))
|
||||
return 3;
|
||||
else if (Strings.startsWith(redirect, "javascript:"))
|
||||
return 4;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
//从请求中设置响应状态和文本属性
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取响应属性码 */
|
||||
public int getResponseStatus()
|
||||
{
|
||||
return responseStatus;
|
||||
}
|
||||
|
||||
/** 获取响应属性文本 */
|
||||
public String getResponseText()
|
||||
{
|
||||
if (!isResponseRedirect())
|
||||
{//不是重定向,直接返回提示信息
|
||||
return alertMsg;
|
||||
}
|
||||
else
|
||||
{//重定向则为redirect#alertMsg
|
||||
if (Validates.isEmptyBlank(alertMsg))
|
||||
return getRedirect(_UTF_8_);
|
||||
else
|
||||
return getRedirect(_UTF_8_) + "#" + alertMsg;
|
||||
}
|
||||
}
|
||||
|
||||
/** 判断响应属性是不是成功 */
|
||||
public boolean isResponseSuccess()
|
||||
{
|
||||
return responseStatus == _0_SUCCESS_;
|
||||
}
|
||||
|
||||
/** 判断响应属性是不是重定向 */
|
||||
public boolean isResponseRedirect()
|
||||
{
|
||||
return responseStatus >= _601_REDIRECT_PARENT_ && responseStatus <= _603_REDIRECT_TOP_;
|
||||
}
|
||||
|
||||
/** 设置响应结果属性,指定状态码但不能小于0,不能填70-699之间已知的状态码 */
|
||||
public void setResponseResult(int responseStatus, String responseText)
|
||||
{
|
||||
if (responseStatus < 0 || (responseStatus >= 70 && responseStatus <= 699))
|
||||
throw new RuntimeException("响应状态码不允许在(小于0和100-300和 304-699)之间数");
|
||||
|
||||
this.responseStatus = responseStatus;
|
||||
setAlertMsg(responseText);
|
||||
}
|
||||
|
||||
/** 设置响应结果属性,指定状态码但不能小于0,不能填70-699之间已知的状态码 */
|
||||
public void setResponseResult(Int result)
|
||||
{
|
||||
this.setResponseResult(result.value(), result.desc());
|
||||
}
|
||||
|
||||
/** 设置响应结果属性,状态码为0,表示成功 */
|
||||
public void setResponseResult(String responseText)
|
||||
{
|
||||
this.responseStatus = _0_SUCCESS_;
|
||||
setAlertMsg(responseText);
|
||||
}
|
||||
|
||||
/** 设置响应结果属性,状态码为699,表示通用的失败 */
|
||||
public void setResponseError(String responseText)
|
||||
{
|
||||
this.responseStatus = _699_ERROR_;
|
||||
setAlertMsg(responseText);
|
||||
}
|
||||
|
||||
/** 设置响应父页重定向,状态码为601 */
|
||||
public void setRedirectParent(String redirect)
|
||||
{
|
||||
this.responseStatus = _601_REDIRECT_PARENT_;
|
||||
setRedirectInner(redirect);
|
||||
}
|
||||
|
||||
/** 设置响应顶页重定向 ,状态码为603*/
|
||||
public void setRedirectTop(String redirect)
|
||||
{
|
||||
this.responseStatus = _603_REDIRECT_TOP_;
|
||||
setRedirectInner(redirect);
|
||||
}
|
||||
|
||||
/** 设置响应重定向前提示错误,状态码为602 */
|
||||
public void setRedirect(String redirect, String error)
|
||||
{
|
||||
if (Validates.isEmptyBlank(error)){
|
||||
setRedirect(redirect);
|
||||
return;
|
||||
}
|
||||
|
||||
setRedirect(redirect);
|
||||
setAlertMsg(error);
|
||||
}
|
||||
|
||||
/** 设置响应父页重定向前提示错误,状态码为601 */
|
||||
public void setRedirectParent(String redirect, String error)
|
||||
{
|
||||
if (Validates.isEmptyBlank(error)){
|
||||
setRedirectParent(redirect);
|
||||
return;
|
||||
}
|
||||
|
||||
this.responseStatus = _601_REDIRECT_PARENT_;
|
||||
setRedirectInner(redirect);
|
||||
setAlertMsg(error);
|
||||
}
|
||||
|
||||
/** 设置响应顶页重定向前提示错误,状态码为603 */
|
||||
public void setRedirectTop(String redirect, String error)
|
||||
{
|
||||
if (Validates.isEmptyBlank(error)){
|
||||
setRedirectTop(redirect);
|
||||
return;
|
||||
}
|
||||
|
||||
this.responseStatus = _603_REDIRECT_TOP_;
|
||||
setRedirectInner(redirect);
|
||||
setAlertMsg(error);
|
||||
}
|
||||
|
||||
protected void destroy()
|
||||
{
|
||||
super.destroy();
|
||||
|
||||
if (paramList != null)
|
||||
{
|
||||
paramList.clear();
|
||||
paramList = null;
|
||||
}
|
||||
|
||||
forward = null;
|
||||
redirect = null;
|
||||
view = null;
|
||||
executeMethod = null;
|
||||
alertMsg = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.zhiqim.kernel.extend.HashMapSS;
|
||||
import org.zhiqim.httpd.util.Scripts;
|
||||
import org.zhiqim.kernel.util.Validates;
|
||||
import org.zhiqim.httpd.validate.OneValidate;
|
||||
import org.zhiqim.httpd.validate.TwoValidate;
|
||||
import org.zhiqim.httpd.validate.Validate;
|
||||
|
||||
/**
|
||||
* 请求中的验证信息
|
||||
* 1.支持在Action/view中增加验证项: request.addValidate(new IsNotEmpty("field", "该字估不允许为空"));
|
||||
* 2.支持设置验证提交后,按钮设置成disabled,因此按钮尽可能使用button来提交,以保证disabled可用
|
||||
* 3.支持验证成功后,弹出确认信息,请设置confirm值
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2016-7-18 新建与整理
|
||||
*/
|
||||
public abstract class HttpRequestValidate extends HttpHeaderInner implements HttpRequest
|
||||
{
|
||||
private String confirm = null; //form提交前确认信息,不为空白表示有效,生成if (confirm(""))此类代码
|
||||
private boolean isGray = true; //form提交后按钮是否为灰色,默认变灰,防止多次提交
|
||||
private List<Validate> validateList; //form表单字段验证列表
|
||||
|
||||
/** 设置确认信息 */
|
||||
public void setValidateConfirm(String confirm)
|
||||
{
|
||||
this.confirm = confirm;
|
||||
}
|
||||
|
||||
/** 使提交按钮变灰 */
|
||||
public void setValidateGray(boolean isGray)
|
||||
{
|
||||
this.isGray = isGray;
|
||||
}
|
||||
|
||||
/** 获取验证列表 */
|
||||
public List<Validate> getValidateList()
|
||||
{
|
||||
return (validateList==null)?new ArrayList<Validate>():validateList;
|
||||
}
|
||||
|
||||
/** 增加验证信息 */
|
||||
public void addValidate(Validate validate)
|
||||
{
|
||||
if (validateList == null)
|
||||
validateList = new ArrayList<>(5);
|
||||
|
||||
validateList.add(validate);
|
||||
}
|
||||
|
||||
/** 检查验证信息 */
|
||||
public boolean chkValidate()
|
||||
{
|
||||
if (validateList == null)
|
||||
return true;
|
||||
|
||||
for (Validate validate : validateList)
|
||||
{
|
||||
if (validate instanceof OneValidate)
|
||||
{
|
||||
OneValidate one = (OneValidate)validate;
|
||||
String value = getParameter(one.getField());
|
||||
if (!one.validate(value))
|
||||
{
|
||||
setAlertMsg(one.getAlertMsg());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (validate instanceof TwoValidate)
|
||||
{
|
||||
TwoValidate two = (TwoValidate)validate;
|
||||
String value1 = getParameter(two.getField());
|
||||
String value2 = getParameter(two.getField2());
|
||||
if (!two.validate(value1, value2))
|
||||
{
|
||||
setAlertMsg(two.getAlertMsg());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** 清除所有的验证信息 */
|
||||
public void clearValidate()
|
||||
{
|
||||
if (validateList != null)
|
||||
validateList.clear();
|
||||
}
|
||||
|
||||
/** 获取验证字符串 */
|
||||
public String getValidateScript()
|
||||
{
|
||||
StringBuilder strb = new StringBuilder();
|
||||
strb.append(Scripts.head());
|
||||
strb.append(Scripts.SCRIPT_HEAD_VALIDATE);
|
||||
|
||||
//创建一个HashMap,利用HashMap不允许重复的约束,使得调用的函数唯一
|
||||
HashMapSS functionMap = new HashMapSS();
|
||||
if (!Validates.isEmpty(validateList))
|
||||
{
|
||||
for (Validate validate : validateList)
|
||||
{
|
||||
strb.append(validate.getScript());
|
||||
functionMap.put(validate.getName(), validate.getFunction());
|
||||
}
|
||||
}
|
||||
|
||||
if (!Validates.isEmpty(confirm))
|
||||
{//增加确认提示
|
||||
strb.append(Scripts.getConfirm(confirm));
|
||||
}
|
||||
|
||||
if (isGray)
|
||||
{// 使提交按钮变灰
|
||||
strb.append(Scripts.getGraySubmit(isFirefox()));
|
||||
}
|
||||
|
||||
strb.append(Scripts.SCRIPT_TAIL_VALIDATE);
|
||||
|
||||
//变灰和恢复两个函数
|
||||
strb.append(Scripts.setFormButtonGray());
|
||||
strb.append(Scripts.setFormButtonResume());
|
||||
|
||||
//验证函数
|
||||
for (String function : functionMap.values())
|
||||
{
|
||||
strb.append(function);
|
||||
}
|
||||
|
||||
if (strb.length() >= 4 && "\r\n\r\n".equals(strb.substring(strb.length() - 4)))
|
||||
{//去掉可能的最后是两个\r\n的一个\r\n
|
||||
strb.setLength(strb.length()-2);
|
||||
}
|
||||
|
||||
strb.append(Scripts.tail());
|
||||
return strb.toString();
|
||||
}
|
||||
|
||||
/** 获取验证提交脚本 */
|
||||
public String getValidateSubmitScript()
|
||||
{
|
||||
StringBuilder strb = new StringBuilder();
|
||||
strb.append(Scripts.head());
|
||||
strb.append(Scripts.SCRIPT_HEAD_SUBMIT);
|
||||
|
||||
//创建一个HashMap,利用HashMap不允许重复的约束,使得调用的函数唯一
|
||||
HashMapSS functionMap = new HashMapSS();
|
||||
if (!Validates.isEmpty(validateList))
|
||||
{
|
||||
for (Validate validate : validateList)
|
||||
{
|
||||
strb.append(validate.getScript());
|
||||
functionMap.put(validate.getName(), validate.getFunction());
|
||||
}
|
||||
}
|
||||
|
||||
if (Validates.isEmpty(confirm))
|
||||
{
|
||||
if (isGray)
|
||||
{// 使提交按钮变灰
|
||||
strb.append(Scripts.getGraySubmit(isFirefox()));
|
||||
}
|
||||
|
||||
strb.append(_FOUR_).append("form.submit();").append(_BR_);
|
||||
}
|
||||
else
|
||||
{//增加确认提示
|
||||
strb.append(_FOUR_).append("Z.confirm(\"").append(confirm).append("\", function()").append(_BR_);
|
||||
strb.append(_FOUR_).append("{").append(_BR_);
|
||||
|
||||
if (isGray)
|
||||
{
|
||||
if (!isFirefox())
|
||||
{//非火狐直接变灰
|
||||
strb.append(_FOUR_).append(_FOUR_).append("setFormButtonGray(form);").append(_BR_);
|
||||
}
|
||||
else
|
||||
{//火狐检查是否有F && Z.onload,否则回退没办法恢复
|
||||
strb.append(_FOUR_).append(_FOUR_).append("if (Z && Z.onload)").append(_BR_)
|
||||
.append(_FOUR_).append(_FOUR_).append("{//firefox要求F && Z.onload时才支持提交变灰和回退恢复").append(_BR_).append(_BR_)
|
||||
//变灰
|
||||
.append(_FOUR_).append(_FOUR_).append(_FOUR_).append("setFormButtonGray(form);").append(_BR_)
|
||||
//回退
|
||||
.append(_FOUR_).append(_FOUR_).append(_FOUR_).append("Z.onload(function(form){setFormButtonResume(form);}, form);").append(_BR_)
|
||||
.append(_FOUR_).append(_FOUR_).append("}").append(_BR_).append(_BR_);
|
||||
}
|
||||
}
|
||||
|
||||
strb.append(_FOUR_).append(_FOUR_).append("form.submit();").append(_BR_);
|
||||
strb.append(_FOUR_).append("});").append(_BR_);
|
||||
}
|
||||
|
||||
strb.append(Scripts.SCRIPT_TAIL_SUBMIT);
|
||||
|
||||
//变灰和恢复两个函数
|
||||
strb.append(Scripts.setFormButtonGray());
|
||||
strb.append(Scripts.setFormButtonResume());
|
||||
|
||||
//验证函数
|
||||
for (String function : functionMap.values())
|
||||
{
|
||||
strb.append(function);
|
||||
}
|
||||
|
||||
if (strb.length() >= 4 && "\r\n\r\n".equals(strb.substring(strb.length() - 4)))
|
||||
{//去掉可能的最后是两个\r\n的一个\r\n
|
||||
strb.setLength(strb.length()-2);
|
||||
}
|
||||
|
||||
strb.append(Scripts.tail());
|
||||
return strb.toString();
|
||||
}
|
||||
|
||||
protected void destroy()
|
||||
{
|
||||
if (validateList != null)
|
||||
{
|
||||
validateList.clear();
|
||||
validateList = null;
|
||||
}
|
||||
|
||||
confirm = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import org.zhiqim.httpd.entities.ClassResourceEntity;
|
||||
import org.zhiqim.httpd.entities.FileResourceEntity;
|
||||
|
||||
import org.zhiqim.kernel.util.Files;
|
||||
import org.zhiqim.kernel.util.Resources;
|
||||
import org.zhiqim.kernel.util.Strings;
|
||||
import org.zhiqim.kernel.util.Validates;
|
||||
|
||||
/**
|
||||
* HTTP资源,包括资源索引,资源类型和资源路径
|
||||
*
|
||||
* 以便HttpContext支持多个资源目录,从而实现资源组件化
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public class HttpResource implements HttpdConstants
|
||||
{
|
||||
public static final HttpResourceCompor _resourceCompor = new HttpResourceCompor();
|
||||
public static final FileResourceEntity _fileResource = new FileResourceEntity();
|
||||
public static final ClassResourceEntity _classResource = new ClassResourceEntity();
|
||||
|
||||
private int resourceIndex;
|
||||
private String resourceType;//classpath|directory
|
||||
private String resourcePath;
|
||||
|
||||
public HttpResource(String resourceType, String resourcePath)
|
||||
{
|
||||
this.resourceType = resourceType;
|
||||
this.resourcePath = Strings.removeEndsWith(resourcePath, "/");
|
||||
}
|
||||
|
||||
public HttpResource(int resourceIndex, String resourceType, String resourcePath)
|
||||
{
|
||||
this.resourceIndex = resourceIndex;
|
||||
this.resourceType = resourceType;
|
||||
this.resourcePath = Strings.removeEndsWith(resourcePath, "/");
|
||||
}
|
||||
|
||||
public boolean isValid()
|
||||
{
|
||||
return Validates.isNotEmpty(resourcePath) && (_CLASSPATH_.equals(resourceType) || _DIRECTORY_.equals(resourceType));
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
//业务处理等方法
|
||||
/********************************************************************/
|
||||
|
||||
/**
|
||||
* 在该资源内处理请求
|
||||
*
|
||||
* @param header 请求头
|
||||
* @param sender 响应发送器
|
||||
* @return =true表示处理到,=false表示不在该资源内
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public boolean handleResource(HttpHeader header, HttpSender sender) throws IOException
|
||||
{
|
||||
//1.如果未配置资源直接返回false
|
||||
if (resourceType == null || resourcePath == null)
|
||||
return false;
|
||||
|
||||
//2.先查找资源是否存在
|
||||
String path = resourcePath + header.getPathInContext();
|
||||
path = URLDecoder.decode(path, header.getCharacterEncoding());
|
||||
|
||||
if (isClasspath())
|
||||
{//classpath
|
||||
if (!Resources.exists(HttpResource.class, path))
|
||||
return false;
|
||||
|
||||
if (header.isMethodHead())
|
||||
{//如果HEAD,直接返回成功
|
||||
sender.sendHeader(_200_OK_);
|
||||
return true;
|
||||
}
|
||||
|
||||
((HttpHeaderInner)header).setPathOnResource(path);
|
||||
_classResource.handle(header, sender);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{//dir
|
||||
if (!Files.isFile(path))
|
||||
return false;
|
||||
|
||||
if (header.isMethodHead())
|
||||
{//如果HEAD,直接返回成功
|
||||
sender.sendHeader(_200_OK_);
|
||||
return true;
|
||||
}
|
||||
|
||||
((HttpHeaderInner)header).setPathOnResource(path);
|
||||
_fileResource.handle(header, sender);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取该资源内的资源字符串
|
||||
*
|
||||
* @param path 请求
|
||||
* @return =null表示不在该资源内,!=null表示在该资源内并读取到内容
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public String getResourceString(String path) throws IOException
|
||||
{
|
||||
return getResourceString(path, _UTF_8_);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取该资源内的资源字符串
|
||||
*
|
||||
* @param path 请求
|
||||
* @param encoding 编码
|
||||
* @return =null表示不在该资源内,!=null表示在该资源内并读取到内容
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public String getResourceString(String path, String encoding) throws IOException
|
||||
{
|
||||
if (resourcePath == null)
|
||||
return null;
|
||||
|
||||
path = resourcePath + "/" + Strings.removeStartsWith(path, "/");
|
||||
if (isClasspath())
|
||||
{
|
||||
if (!Resources.exists(HttpResource.class, path))
|
||||
return null;
|
||||
|
||||
return Resources.getResourceString(HttpResource.class, path, encoding);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Files.isFile(path))
|
||||
return null;
|
||||
|
||||
return Files.read(path, encoding);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取资源目录下的文件名和目录名,目录名以/结尾,用于显示目录下列表
|
||||
*
|
||||
* @param folderPath 目录地址
|
||||
* @return 名称列表
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public List<String> getResourceNameList(String folderPath) throws IOException
|
||||
{
|
||||
if (resourcePath == null)
|
||||
return new ArrayList<>(0);
|
||||
|
||||
folderPath = resourcePath + "/" + Strings.removeStartsWith(folderPath, "/");
|
||||
if (isClasspath())
|
||||
{
|
||||
if (!Resources.exists(HttpResource.class, folderPath))
|
||||
return new ArrayList<>(0);
|
||||
|
||||
return Resources.getResourceNameList(HttpResource.class, folderPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Files.isDirectory(folderPath))
|
||||
return new ArrayList<>(0);
|
||||
|
||||
File folder = new File(folderPath);
|
||||
File[] files = folder.listFiles(new FileFilter(){public boolean accept(File file){return !file.isHidden();}});
|
||||
if (files == null)
|
||||
return new ArrayList<>(0);
|
||||
|
||||
List<String> nameList = new ArrayList<>();
|
||||
for (File file : files)
|
||||
{
|
||||
if (file.isDirectory())
|
||||
nameList.add(file.getName()+"/");
|
||||
else
|
||||
nameList.add(file.getName());
|
||||
}
|
||||
|
||||
return nameList;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
//属性 get & set 等方法
|
||||
/********************************************************************/
|
||||
|
||||
public boolean isClasspath()
|
||||
{
|
||||
return _CLASSPATH_.equals(resourceType);
|
||||
}
|
||||
|
||||
public int getResourceIndex()
|
||||
{
|
||||
return resourceIndex;
|
||||
}
|
||||
public void setResourceIndex(int resourceIndex)
|
||||
{
|
||||
this.resourceIndex = resourceIndex;
|
||||
}
|
||||
public String getResourceType()
|
||||
{
|
||||
return resourceType;
|
||||
}
|
||||
public void setResourceType(String resourceType)
|
||||
{
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
public String getResourcePath()
|
||||
{
|
||||
return resourcePath;
|
||||
}
|
||||
public void setResourcePath(String resourcePath)
|
||||
{
|
||||
this.resourcePath = resourcePath;
|
||||
}
|
||||
|
||||
/********************************************************************/
|
||||
//定义HTTP资源等resourcePath & resourceType都相等时即对象相等
|
||||
/********************************************************************/
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((resourcePath == null) ? 0 : resourcePath.hashCode());
|
||||
result = prime * result + ((resourceType == null) ? 0 : resourceType.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
HttpResource other = (HttpResource) obj;
|
||||
if (resourcePath == null)
|
||||
{
|
||||
if (other.resourcePath != null)
|
||||
return false;
|
||||
}
|
||||
else if (!resourcePath.equals(other.resourcePath))
|
||||
return false;
|
||||
if (resourceType == null)
|
||||
{
|
||||
if (other.resourceType != null)
|
||||
return false;
|
||||
}
|
||||
else if (!resourceType.equals(other.resourceType))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** 按索引排序 */
|
||||
private static class HttpResourceCompor implements Comparator<HttpResource>
|
||||
{
|
||||
public int compare(HttpResource o1, HttpResource o2)
|
||||
{
|
||||
return o1.getResourceIndex() - o2.getResourceIndex();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
|
||||
/**
|
||||
* HTTP响应接口定义
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2016-7-19 新建与整理
|
||||
*/
|
||||
public interface HttpResponse extends HttpSender
|
||||
{
|
||||
/***********************************************************************/
|
||||
// 关联连接信息
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取连接编号 */
|
||||
public String getId();
|
||||
|
||||
/** 获取当前请求 */
|
||||
public HttpRequest getRequest();
|
||||
|
||||
/** 获取上下文环境 */
|
||||
public HttpContext getContext();
|
||||
|
||||
/***********************************************************************/
|
||||
// 状态处理和判断
|
||||
/***********************************************************************/
|
||||
|
||||
/** 是否已提交 */
|
||||
public boolean isCommitted();
|
||||
|
||||
/** 是否可编辑 */
|
||||
public boolean isEditable();
|
||||
|
||||
/***********************************************************************/
|
||||
// 设置状态或,或重定向,或错误重定向
|
||||
/***********************************************************************/
|
||||
|
||||
/** 编码URL,增加非useCookie时有可能的jsessionid,在URL跳转时需要 */
|
||||
public String encodeURL(String url);
|
||||
|
||||
/***********************************************************************/
|
||||
// 设置头部信息
|
||||
/***********************************************************************/
|
||||
|
||||
/** 设置缓存控制域 */
|
||||
public void setCacheControl(String value);
|
||||
|
||||
/** 设置缓存控制域为私有 */
|
||||
public void setCacheControlPrivate();
|
||||
|
||||
/** 删除头部域 */
|
||||
public void removeHeader(String key);
|
||||
|
||||
/** 获取头部域 */
|
||||
public String getHeader(String key);
|
||||
|
||||
/** 判断是否有头部域 */
|
||||
public boolean hasHeader(String key);
|
||||
|
||||
/** 获取编码格式 */
|
||||
public String getCharacterEncoding();
|
||||
|
||||
/***********************************************************************/
|
||||
// 设置Cookie
|
||||
/***********************************************************************/
|
||||
|
||||
/** 增加cookie值,浏览器关闭即失效 */
|
||||
public void addCookie(String name, String value);
|
||||
|
||||
/** 增加cookie值,指定保存时间 */
|
||||
public void addCookie(String name, String value, int seconds);
|
||||
|
||||
/** 增加Cookie值 */
|
||||
public void addCookie(HttpCookie cookie);
|
||||
|
||||
/** 删除Cookie值 */
|
||||
public void removeCookie(String name);
|
||||
|
||||
/** 清空Cookie */
|
||||
public void clearCookie();
|
||||
}
|
||||
@@ -0,0 +1,533 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.zhiqim.kernel.util.Asserts;
|
||||
import org.zhiqim.kernel.util.Validates;
|
||||
|
||||
/**
|
||||
* HTTP响应类
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public class HttpResponseImpl implements HttpResponse
|
||||
{
|
||||
private HttpRequestAbs request;
|
||||
private HttpSenderImpl sender;
|
||||
private HttpContext context;
|
||||
private List<HttpCookie> cookies;
|
||||
|
||||
private boolean addSessionIdToCookie;
|
||||
private boolean addCookieToSender;
|
||||
|
||||
public HttpResponseImpl(HttpRequestAbs request)
|
||||
{
|
||||
this.request = request;
|
||||
this.sender = (HttpSenderImpl)request.getSender();
|
||||
this.context = request.getContext();
|
||||
|
||||
this.cookies = new ArrayList<HttpCookie>();
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
// 关联连接信息
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取连接编号 */
|
||||
public String getId()
|
||||
{
|
||||
return request.getId();
|
||||
}
|
||||
|
||||
/** 获取当前请求 */
|
||||
public HttpRequest getRequest()
|
||||
{
|
||||
return request;
|
||||
}
|
||||
|
||||
/** 获取上下文环境 */
|
||||
public HttpContext getContext()
|
||||
{
|
||||
return context;
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
// 状态处理和判断
|
||||
/***********************************************************************/
|
||||
|
||||
/** 是否可编辑 */
|
||||
public boolean isEditable()
|
||||
{
|
||||
return request != null && request.isEditable();
|
||||
}
|
||||
|
||||
/** 是否已提交 */
|
||||
public boolean isCommitted()
|
||||
{
|
||||
return request == null || request.isCommitted();
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
// 设置状态或,或重定向,或错误重定向
|
||||
/***********************************************************************/
|
||||
|
||||
/**
|
||||
* 单独设置状态,通过setStatus,write和commit完成操作
|
||||
*/
|
||||
public void setStatus(int code)
|
||||
{
|
||||
sender.setStatus(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发生错误,返回错误码和标准的错误信息
|
||||
*
|
||||
* @param code 错误码
|
||||
* @throws IOException 可能的异常
|
||||
*/
|
||||
public void sendError(int code) throws IOException
|
||||
{
|
||||
sendError(code, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发生错误,返回错误状态和一句错误描述,如果描述为null,则取标准错误描述
|
||||
*
|
||||
* @param code 错误码
|
||||
* @param message 错误信息
|
||||
* @throws IOException 可能的异常
|
||||
*/
|
||||
public void sendError(int code, String message) throws IOException
|
||||
{
|
||||
sender.sendError(code, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送错误信息,内容为HTML格式
|
||||
*
|
||||
* @param code 响应码
|
||||
* @throws IOException 可能的异常
|
||||
*/
|
||||
public void sendErrorHTML(int code) throws IOException
|
||||
{
|
||||
sender.sendErrorHTML(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送错误信息,内容为HTML格式
|
||||
*
|
||||
* @param code 响应码
|
||||
* @param reason 响应原因
|
||||
* @throws IOException 可能的异常
|
||||
*/
|
||||
public void sendErrorHTML(int code, String reason) throws IOException
|
||||
{
|
||||
sender.sendErrorHTML(code, reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端重定向,将资源指身一个永久URI,采用302把URI写在location消息头中
|
||||
*
|
||||
* @param location 重定向连接地址
|
||||
* @throws IOException 可能的异常
|
||||
*/
|
||||
public void sendRedirect(String location) throws IOException
|
||||
{
|
||||
Asserts.asState(!isCommitted()?null:"已提交不允许再提交");
|
||||
|
||||
this.addCookieSessionId();
|
||||
this.addCookieToSender();
|
||||
sender.sendRedirect(encodeURL(location));
|
||||
}
|
||||
|
||||
/**
|
||||
* 只返回消息头,如304等,会清空内容
|
||||
*
|
||||
* @param code 响应码,可以是200表示成功
|
||||
* @throws IOException 可能的异常
|
||||
*/
|
||||
public void sendHeader(int code) throws IOException
|
||||
{
|
||||
this.addCookieSessionId();
|
||||
this.addCookieToSender();
|
||||
sender.sendHeader(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 一般用于返回200-207的成功码和提示的一个内容,和sendError不同的是sendError的reason=content,而sendSuccess的reason=默认值
|
||||
*
|
||||
* @param code 成功码
|
||||
* @param content 内容
|
||||
* @throws IOException 可能的异常
|
||||
*/
|
||||
public void sendContent(int code, String content) throws IOException
|
||||
{
|
||||
this.addCookieSessionId();
|
||||
this.addCookieToSender();
|
||||
sender.sendContent(code, content);
|
||||
}
|
||||
|
||||
/** 编码URL,增加非useCookie时有可能的jsessionid,在URL跳转时需要 */
|
||||
public String encodeURL(String url)
|
||||
{
|
||||
if (context == null)
|
||||
return url;
|
||||
|
||||
HttpSessionManager sessionManager = context.getSessionManager();
|
||||
if (sessionManager == null)
|
||||
return url;
|
||||
|
||||
if (context.isCookieUse())
|
||||
return url;
|
||||
|
||||
HttpSession session = getRequest().getSession();
|
||||
if (session == null)
|
||||
return url;
|
||||
|
||||
String sessionId = session.getId();
|
||||
if (sessionId == null)
|
||||
return url;
|
||||
|
||||
int ind = url.indexOf("?");
|
||||
if (ind == -1)
|
||||
url = url + "?"+sessionManager.getSessionIdName()+"=" + sessionId;
|
||||
else//存在参数
|
||||
url = url + "&"+sessionManager.getSessionIdName()+"=" + sessionId;
|
||||
return url;
|
||||
}
|
||||
|
||||
/** 获取响应状态码 */
|
||||
public int getStatus()
|
||||
{
|
||||
return sender.getStatus();
|
||||
}
|
||||
|
||||
/** 获取状态描述 */
|
||||
public String getReason()
|
||||
{
|
||||
return sender.getReason();
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
// 设置头部信息
|
||||
/***********************************************************************/
|
||||
|
||||
/** 设置头部域 */
|
||||
public void setHeader(String key, Object value)
|
||||
{
|
||||
sender.setHeader(key, value);
|
||||
}
|
||||
|
||||
/** 设置头部日期格式域 */
|
||||
public void setDateHeader(String key, long value)
|
||||
{
|
||||
sender.setDateHeader(key, value);
|
||||
}
|
||||
|
||||
/** 设置缓存控制域 */
|
||||
public void setCacheControl(String value)
|
||||
{
|
||||
setHeader(_CACHE_CONTROL_, value);
|
||||
}
|
||||
|
||||
/** 设置缓存控制域为私有 */
|
||||
public void setCacheControlPrivate()
|
||||
{
|
||||
setHeader(_PRAGMA_, _PRIVATE_);
|
||||
setHeader(_CACHE_CONTROL_, _PRIVATE_);
|
||||
}
|
||||
|
||||
/** 设置头部域,增加一个属性 */
|
||||
public void addHeader(String key, Object value)
|
||||
{
|
||||
sender.addHeader(key, value);
|
||||
}
|
||||
|
||||
/** 设置头部日期格式域,增加一个日期类型的属性 */
|
||||
public void addDateHeader(String key, long value)
|
||||
{
|
||||
sender.addDateHeader(key, value);
|
||||
}
|
||||
|
||||
/** 删除头部域 */
|
||||
public void removeHeader(String key)
|
||||
{
|
||||
sender.removeHeader(key);
|
||||
}
|
||||
|
||||
/** 获取头部域 */
|
||||
public String getHeader(String key)
|
||||
{
|
||||
return sender.getHeader(key);
|
||||
}
|
||||
|
||||
/** 判断是否有头部域 */
|
||||
public boolean hasHeader(String key)
|
||||
{
|
||||
return sender.hasHeader(key);
|
||||
}
|
||||
|
||||
/** 设置编码格式 */
|
||||
public void setCharacterEncoding(String encoding)
|
||||
{
|
||||
sender.setCharacterEncoding(encoding);
|
||||
}
|
||||
|
||||
/** 获取编码格式 */
|
||||
public String getCharacterEncoding()
|
||||
{
|
||||
String encoding = sender.getCharacterEncoding();
|
||||
if (Validates.isEmptyBlank(encoding))
|
||||
encoding = getRequest().getCharacterEncoding();
|
||||
|
||||
return Validates.isEmptyBlank(encoding)?_UTF_8_:encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置内容类型,会增加默认的字符集到消息头中
|
||||
*
|
||||
* @param contentType 内容类型
|
||||
*/
|
||||
public void setContentType(String contentType)
|
||||
{
|
||||
sender.setContentType(contentType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置内容类型,不设置字符集到消息头中
|
||||
*
|
||||
* @param contentType 内容类型
|
||||
*/
|
||||
public void setContentTypeNoCharset(String contentType)
|
||||
{
|
||||
sender.setContentTypeNoCharset(contentType);
|
||||
}
|
||||
|
||||
/** 获取内容长度 */
|
||||
public long getFlushLength()
|
||||
{
|
||||
return sender.getFlushLength();
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
// 设置Cookie
|
||||
/***********************************************************************/
|
||||
|
||||
/** 增加cookie值,浏览器关闭即失效 */
|
||||
public void addCookie(String name, String value)
|
||||
{
|
||||
cookies.add(new HttpCookie(name, value));
|
||||
}
|
||||
/**
|
||||
* 增加cookie值
|
||||
*
|
||||
* @param name 名称
|
||||
* @param value 值
|
||||
* @param seconds 存活时间,单位:秒
|
||||
*/
|
||||
public void addCookie(String name, String value, int seconds)
|
||||
{
|
||||
HttpCookie cookie = new HttpCookie(name, value);
|
||||
cookie.setMaxAge(seconds);
|
||||
|
||||
addCookie(cookie);
|
||||
}
|
||||
|
||||
/** 增加Cookie值 */
|
||||
public void addCookie(HttpCookie cookie)
|
||||
{
|
||||
cookies.add(cookie);
|
||||
}
|
||||
|
||||
/** 删除Cookie值 */
|
||||
public void removeCookie(String name)
|
||||
{
|
||||
for (Iterator<HttpCookie> it = cookies.iterator();it.hasNext();)
|
||||
{
|
||||
HttpCookie cookie = it.next();
|
||||
if (name.equals(cookie.getName()))
|
||||
it.remove();
|
||||
}
|
||||
|
||||
addCookie(name, null, -1);
|
||||
}
|
||||
|
||||
/** 清空Cookie */
|
||||
public void clearCookie()
|
||||
{
|
||||
cookies.clear();
|
||||
}
|
||||
|
||||
/** 把cookie写入到sender */
|
||||
private void addCookieToSender()
|
||||
{
|
||||
if (addCookieToSender || cookies.isEmpty() || context == null || !context.isCookieUse())
|
||||
return;
|
||||
|
||||
//要求Cookies不为空,且当context != null 时约定使用Cookie;
|
||||
String host = context.getCookieDomain();
|
||||
if (Validates.isEmpty(host))
|
||||
host = getRequest().getHostOnly();
|
||||
|
||||
String path = context.getCookiePath();
|
||||
if (Validates.isEmpty(path))
|
||||
path = context.getContextPath();
|
||||
|
||||
int port = context.getCookiePort();
|
||||
if (port == 0)
|
||||
port = getRequest().getPort();
|
||||
|
||||
for (HttpCookie cookie : cookies)
|
||||
{
|
||||
sender.addMultiHeader(_SET_COOKIE_, cookie.getResponseValue(path, host, port));
|
||||
}
|
||||
|
||||
addCookieToSender = true;
|
||||
}
|
||||
|
||||
/** 把sessionId组装成cookie */
|
||||
private void addCookieSessionId()
|
||||
{
|
||||
if (addSessionIdToCookie || context == null || !context.isCookieUse())
|
||||
return;
|
||||
|
||||
HttpSessionManager sessionManager = context.getSessionManager();
|
||||
if (sessionManager == null)
|
||||
return;
|
||||
|
||||
HttpSession session = request.getSession();
|
||||
if (session == null)
|
||||
return;
|
||||
|
||||
//有会话要求维持时,放置到Cookies中
|
||||
String sessionId = session.getId();
|
||||
addCookie(new HttpCookie(sessionManager.getSessionIdName(), sessionId));
|
||||
|
||||
//如果有浸入式修改了sessionId,则清理老会话,设置新会话
|
||||
String oldSessionId = session.getOldSessionId();
|
||||
if (oldSessionId != null)
|
||||
{
|
||||
if (!sessionId.equals(oldSessionId))
|
||||
sessionManager.invalidateSession(oldSessionId);
|
||||
session.clearOldSessionId();
|
||||
sessionManager.setSession(session);
|
||||
}
|
||||
|
||||
addSessionIdToCookie = true;
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
// 数据流处理,包括写入、打印和提交等
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取输出流 */
|
||||
public OutputStream getOutputStream()
|
||||
{
|
||||
return sender.getOutputStream();
|
||||
}
|
||||
|
||||
/** 写内容字节方式 */
|
||||
public void write(byte[] b) throws IOException
|
||||
{
|
||||
addCookieSessionId();
|
||||
addCookieToSender();
|
||||
|
||||
sender.write(b);
|
||||
}
|
||||
|
||||
/** 写内容加回车换行 */
|
||||
public void println(String str) throws IOException
|
||||
{
|
||||
addCookieSessionId();
|
||||
addCookieToSender();
|
||||
|
||||
sender.println(str);
|
||||
}
|
||||
|
||||
/** 写回车换行 */
|
||||
public void println() throws IOException
|
||||
{
|
||||
addCookieSessionId();
|
||||
addCookieToSender();
|
||||
|
||||
sender.println();
|
||||
}
|
||||
|
||||
/** 写内容,无回车换行 */
|
||||
public void print(String str) throws IOException
|
||||
{
|
||||
addCookieSessionId();
|
||||
addCookieToSender();
|
||||
|
||||
sender.print(str);
|
||||
}
|
||||
|
||||
/** 提交响应 */
|
||||
public void commit() throws IOException
|
||||
{
|
||||
if (isCommitted())
|
||||
return;
|
||||
|
||||
addCookieSessionId();
|
||||
addCookieToSender();
|
||||
sender.commit();
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
// toString
|
||||
/***********************************************************************/
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return sender.toString();
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
// 内部调用的方法,不通过HttpResponse公开
|
||||
/***********************************************************************/
|
||||
|
||||
/** 销毁 */
|
||||
void destroy()
|
||||
{
|
||||
if (cookies != null)
|
||||
{
|
||||
cookies.clear();
|
||||
cookies = null;
|
||||
}
|
||||
|
||||
//引用置空
|
||||
request = null;
|
||||
sender = null;
|
||||
context = null;
|
||||
}
|
||||
|
||||
byte[] buildChunkedHeader(boolean chunked)
|
||||
{
|
||||
return sender.buildChunkedHeader(chunked);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* HTTP发送器
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-2-27 新建与整理
|
||||
*/
|
||||
public interface HttpSender extends HttpdConstants
|
||||
{
|
||||
/** 设置状态 */
|
||||
public void setStatus(int code);
|
||||
|
||||
/** 设置编码格式 */
|
||||
public void setCharacterEncoding(String encoding);
|
||||
|
||||
/** 获取响应状态 */
|
||||
public int getStatus();
|
||||
|
||||
/** 获取响应原因 */
|
||||
public String getReason();
|
||||
|
||||
/***********************************************************************/
|
||||
// 设置头部信息
|
||||
/***********************************************************************/
|
||||
|
||||
/** 设置头部域 */
|
||||
public void setHeader(String key, Object value);
|
||||
|
||||
/** 设置头部日期格式域 */
|
||||
public void setDateHeader(String key, long value);
|
||||
|
||||
/** 设置头部域,增加一个属性 */
|
||||
public void addHeader(String key, Object value);
|
||||
|
||||
/** 设置头部日期格式域,增加一个日期类型的属性 */
|
||||
public void addDateHeader(String key, long value);
|
||||
|
||||
/**
|
||||
* 设置内容类型,会增加默认的字符集到消息头中
|
||||
*
|
||||
* @param contentType 内容类型
|
||||
*/
|
||||
public void setContentType(String contentType);
|
||||
|
||||
/**
|
||||
* 设置内容类型,不设置字符集到消息头中
|
||||
*
|
||||
* @param contentType 内容类型
|
||||
*/
|
||||
public void setContentTypeNoCharset(String contentType);
|
||||
|
||||
/***********************************************************************/
|
||||
// sendError & sendRedirect
|
||||
/***********************************************************************/
|
||||
|
||||
/**
|
||||
* 发送错误信息
|
||||
*
|
||||
* @param code 编码
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public void sendError(int code) throws IOException;
|
||||
|
||||
/**
|
||||
* 发送错误信息
|
||||
*
|
||||
* @param code 编码
|
||||
* @param reason 原因
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public void sendError(int code, String reason) throws IOException;
|
||||
|
||||
/**
|
||||
* 发送错误信息,内容为HTML格式
|
||||
*
|
||||
* @param code 响应码
|
||||
* @throws IOException 可能的异常
|
||||
*/
|
||||
public void sendErrorHTML(int code) throws IOException;
|
||||
|
||||
/**
|
||||
* 发送错误信息,内容为HTML格式
|
||||
*
|
||||
* @param code 响应码
|
||||
* @param reason 响应原因
|
||||
* @throws IOException 可能的异常
|
||||
*/
|
||||
public void sendErrorHTML(int code, String reason) throws IOException;
|
||||
|
||||
/**
|
||||
* 发送重定向信息
|
||||
*
|
||||
* @param location 重定向URL
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public void sendRedirect(String location) throws IOException;
|
||||
|
||||
/**
|
||||
* 发送消息头,如304等,会清空内容
|
||||
*
|
||||
* @param code 响应码,可以是200表示成功
|
||||
* @throws IOException 可能的异常
|
||||
*/
|
||||
public void sendHeader(int code) throws IOException;
|
||||
|
||||
/**
|
||||
* 一般用于返回200-207的成功码和提示的一个内容,和sendError不同的是sendError的reason=content,而sendSuccess的reason=默认值
|
||||
*
|
||||
* @param code 成功码
|
||||
* @param content 内容
|
||||
* @throws IOException 可能的异常
|
||||
*/
|
||||
public void sendContent(int code, String content) throws IOException;
|
||||
|
||||
/***********************************************************************/
|
||||
// write & print & commit
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取输出流 */
|
||||
public OutputStream getOutputStream();
|
||||
|
||||
/** 写内容字节方式 */
|
||||
public void write(byte[] b) throws IOException;
|
||||
|
||||
/** 写内容加回车换行 */
|
||||
public void println(String str) throws IOException;
|
||||
|
||||
/** 写回车换行 */
|
||||
public void println() throws IOException;
|
||||
|
||||
/** 写内容,无回车换行 */
|
||||
public void print(String str) throws IOException;
|
||||
|
||||
/** 提交流 */
|
||||
public void commit() throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,533 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.zhiqim.httpd.constants.HttpStatus;
|
||||
import org.zhiqim.kernel.util.Asserts;
|
||||
import org.zhiqim.kernel.util.DateTimes;
|
||||
import org.zhiqim.kernel.util.Strings;
|
||||
import org.zhiqim.kernel.util.Urls;
|
||||
import org.zhiqim.kernel.util.Validates;
|
||||
|
||||
/**
|
||||
* HTTP发送器
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2018-9-11 新建与整理
|
||||
*/
|
||||
public class HttpSenderImpl implements HttpSender
|
||||
{
|
||||
private HttpHeaderAbs header;
|
||||
private HttpOutputStream output;
|
||||
|
||||
private String version = _HTTP_1_1_;
|
||||
private int status = _200_OK_;
|
||||
private String reason = _200_DESC_;
|
||||
private String characterEncoding = _UTF_8_;
|
||||
|
||||
//消息头
|
||||
private HashMap<String, String> headers;
|
||||
private StringBuilder headerBuffer;
|
||||
|
||||
public HttpSenderImpl(HttpHeaderAbs header, boolean autoClose)
|
||||
{
|
||||
this.header = header;
|
||||
this.output = header.getOutputStream();
|
||||
this.output.setSender(this);
|
||||
|
||||
this.headers = new HashMap<>(5);
|
||||
this.headers.put(_SERVER_, _ZHTTPD_);
|
||||
if (autoClose)
|
||||
{//是否执行完自动关闭
|
||||
this.headers.put(_CONNECTION_, _CLOSE_);
|
||||
}
|
||||
|
||||
this.headerBuffer = new StringBuilder();
|
||||
}
|
||||
|
||||
/** 是否已提交 */
|
||||
public boolean isCommitted()
|
||||
{
|
||||
return header.isCommitted();
|
||||
}
|
||||
|
||||
/** 是否可编辑 */
|
||||
public boolean isEditable()
|
||||
{
|
||||
return header.isEditable();
|
||||
}
|
||||
|
||||
/** 是否支持响应GZIP */
|
||||
public boolean isResponseGZip()
|
||||
{
|
||||
return header.isResponseGZip();
|
||||
}
|
||||
|
||||
/** 提交流 */
|
||||
public void commit() throws IOException
|
||||
{
|
||||
if (header.isCommitted())
|
||||
return;
|
||||
|
||||
header.setStep(_11_COMMITTED_);
|
||||
output.commit();
|
||||
|
||||
if (isClose())
|
||||
{//是否提交后关闭连接
|
||||
header.close();
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
// 状态&版本&编码
|
||||
/***********************************************************************/
|
||||
|
||||
public void setStatus(int code)
|
||||
{
|
||||
this.status = code;
|
||||
this.reason = HttpStatus.getStatusMsg(code);
|
||||
}
|
||||
|
||||
public int getStatus()
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setVersion(String version)
|
||||
{
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getReason()
|
||||
{
|
||||
return reason;
|
||||
}
|
||||
|
||||
public String getCharacterEncoding()
|
||||
{
|
||||
return characterEncoding;
|
||||
}
|
||||
|
||||
public long getFlushLength()
|
||||
{
|
||||
return output.getOutputLength();
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
// 设置头部信息
|
||||
/***********************************************************************/
|
||||
|
||||
/** 设置头部域 */
|
||||
public void setHeader(String key, Object value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
headers.put(key, Strings.valueOf(value));
|
||||
}
|
||||
|
||||
/** 获取头部域 */
|
||||
public String getHeader(String key)
|
||||
{
|
||||
return headers.get(key);
|
||||
}
|
||||
|
||||
/** 判断是否有头部域 */
|
||||
public boolean hasHeader(String key)
|
||||
{
|
||||
return headers.containsKey(key);
|
||||
}
|
||||
|
||||
/** 是否关闭连接(没有连接属性和指明关闭的) */
|
||||
public boolean isClose()
|
||||
{
|
||||
String connection = getHeader(_CONNECTION_);
|
||||
return Validates.isEmptyBlank(connection) || _CLOSE_.equalsIgnoreCase(connection);
|
||||
}
|
||||
|
||||
/** 设置头部日期格式域 */
|
||||
public void setDateHeader(String key, long value)
|
||||
{
|
||||
String date = DateTimes.getDateTimeHttp(value);
|
||||
setHeader(key, date);
|
||||
}
|
||||
|
||||
/** 设置头部域,增加一个属性 */
|
||||
public void addHeader(String key, Object value)
|
||||
{
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
String v = getHeader(key);
|
||||
if (v == null)
|
||||
setHeader(key, value);
|
||||
else
|
||||
setHeader(key, v + "," + Strings.valueOf(value));
|
||||
}
|
||||
|
||||
/** 设置头部日期格式域,增加一个日期类型的属性 */
|
||||
public void addDateHeader(String key, long value)
|
||||
{
|
||||
String date = DateTimes.getDateTimeHttp(value);
|
||||
|
||||
String v = getHeader(key);
|
||||
if (v == null)
|
||||
setHeader(key, date);
|
||||
else
|
||||
setHeader(key, v + "," + value);
|
||||
}
|
||||
|
||||
/** 删除头部域 */
|
||||
public void removeHeader(String key)
|
||||
{
|
||||
headers.remove(key);
|
||||
}
|
||||
|
||||
/** 添加复杂的头信息,如cookie等 */
|
||||
public void addMultiHeader(String key, String value)
|
||||
{
|
||||
headerBuffer.append(key).append(_COLON_).append(value).append(_BR_);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置编码格式
|
||||
*
|
||||
* @param encoding 编码格式
|
||||
*/
|
||||
public void setCharacterEncoding(String encoding)
|
||||
{
|
||||
Asserts.assertNotEmptyBlank(encoding, "编码格式不允许为空白");
|
||||
this.characterEncoding = encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置内容类型,会增加默认的字符集到消息头中
|
||||
*
|
||||
* @param contentType 内容类型
|
||||
*/
|
||||
public void setContentType(String contentType)
|
||||
{
|
||||
Asserts.assertNotEmptyBlank(contentType, "内容类型不允许为空白");
|
||||
|
||||
//在contentType中查找encoding,格式为:text/html; charset=UTF-8
|
||||
String mimeType = null;
|
||||
int i0 = contentType.indexOf(';');
|
||||
if (i0 == -1)
|
||||
mimeType = contentType;
|
||||
else
|
||||
{
|
||||
mimeType = contentType.substring(0, i0).trim();
|
||||
int i1 = contentType.indexOf("charset=", i0);
|
||||
if (i1>=0)
|
||||
{//有设置编码则修改为该编码
|
||||
characterEncoding = contentType.substring(i1 + 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (Validates.isEmptyBlank(characterEncoding))
|
||||
setHeader(_CONTENT_TYPE_, mimeType);
|
||||
else
|
||||
setHeader(_CONTENT_TYPE_, mimeType + "; charset="+characterEncoding);
|
||||
}
|
||||
|
||||
/** 设置头部域中内容类型 */
|
||||
public void setContentTypeNoCharset(String contentType)
|
||||
{
|
||||
Asserts.assertNotEmptyBlank(contentType, "内容类型不允许为空白");
|
||||
Asserts.as(contentType.indexOf(";") == -1?null:"内容类型含字符集请调用setContentType方法");
|
||||
|
||||
setHeader(_CONTENT_TYPE_, contentType);
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
// 发送错误&内容
|
||||
/***********************************************************************/
|
||||
|
||||
/**
|
||||
* 发送错误信息
|
||||
*
|
||||
* @param code 编码
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public void sendError(int code) throws IOException
|
||||
{
|
||||
sendError(code, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送错误信息
|
||||
*
|
||||
* @param code 编码
|
||||
* @param reason 原因
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public void sendError(int code, String reason) throws IOException
|
||||
{
|
||||
Asserts.asState(isEditable()?null:"已提交不允许再提交");
|
||||
|
||||
this.status = code;
|
||||
if (Validates.isEmptyBlank(reason))
|
||||
this.reason = HttpStatus.getStatusMsg(code);
|
||||
else
|
||||
this.reason = reason;
|
||||
|
||||
this.clear();
|
||||
this.print(this.reason);
|
||||
this.commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送错误信息,内容为HTML格式
|
||||
*
|
||||
* @param code 响应码
|
||||
* @throws IOException 可能的异常
|
||||
*/
|
||||
public void sendErrorHTML(int code) throws IOException
|
||||
{
|
||||
sendErrorHTML(code, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送错误信息,内容为HTML格式
|
||||
*
|
||||
* @param code 响应码
|
||||
* @param reason 响应原因
|
||||
* @throws IOException 可能的异常
|
||||
*/
|
||||
public void sendErrorHTML(int code, String reason) throws IOException
|
||||
{
|
||||
Asserts.asState(isEditable()?null:"已提交不允许再提交");
|
||||
|
||||
this.status = code;
|
||||
if (Validates.isEmptyBlank(reason))
|
||||
this.reason = HttpStatus.getStatusMsg(code);
|
||||
else
|
||||
this.reason = reason;
|
||||
|
||||
//content
|
||||
StringBuilder strb = new StringBuilder();
|
||||
strb.append(_HTML_5_TYPE_).append(_BR_);
|
||||
strb.append(_HTML).append(_BR_);
|
||||
strb.append(_HEAD).append("<title>Error ").append(code).append("</title>").append(_HEAD).append(_BR_);
|
||||
strb.append(_BODY).append("<h2>Error ").append(reason).append("</h2>").append(BODY_).append(_BR_);
|
||||
strb.append(HTML_).append(_BR_);
|
||||
|
||||
this.clear();
|
||||
this.print(this.reason);
|
||||
this.commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息内容,如200,201等,含内容
|
||||
*
|
||||
* @param code 响应码,可以是200表示成功
|
||||
* @param content 响应内容
|
||||
* @throws IOException 可能的异常
|
||||
*/
|
||||
public void sendContent(int code, String content) throws IOException
|
||||
{
|
||||
Asserts.asState(isEditable()?null:"已提交不允许再提交");
|
||||
|
||||
this.status = code;
|
||||
this.reason = HttpStatus.getStatusMsg(code);
|
||||
|
||||
this.print(content);
|
||||
this.commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送重定向信息
|
||||
*
|
||||
* @param url 重定向URL
|
||||
* @throws IOException 异常
|
||||
*/
|
||||
public void sendRedirect(String url) throws IOException
|
||||
{
|
||||
Asserts.asState(!isCommitted()?null:"已提交不允许再提交");
|
||||
|
||||
this.status = _302_FOUND_;
|
||||
this.reason = _302_DESC_;
|
||||
this.setHeader(_LOCATION_, url);
|
||||
this.setHeader(_PROXY_CONNECTION_, _CLOSE_);
|
||||
this.commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* 只返回消息头,如304等,会清空内容
|
||||
*
|
||||
* @param code 响应码,可以是200表示成功
|
||||
* @throws IOException 可能的异常
|
||||
*/
|
||||
public void sendHeader(int code) throws IOException
|
||||
{
|
||||
Asserts.asState(isEditable()?null:"有提交数据时不允许更新提交内容");
|
||||
|
||||
this.status = code;
|
||||
this.reason = HttpStatus.getStatusMsg(code);
|
||||
|
||||
this.clear();
|
||||
this.commit();
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
// write & print & commit
|
||||
/***********************************************************************/
|
||||
|
||||
/** 获取输出流 */
|
||||
public OutputStream getOutputStream()
|
||||
{
|
||||
return output;
|
||||
}
|
||||
|
||||
/** 写内容字节方式 */
|
||||
public void write(byte[] b) throws IOException
|
||||
{
|
||||
output.write(b);
|
||||
}
|
||||
|
||||
/** 写内容加回车换行 */
|
||||
public void println(String str) throws IOException
|
||||
{
|
||||
output.write(str.getBytes(characterEncoding));
|
||||
output.write(_CRLF_);
|
||||
}
|
||||
|
||||
/** 写回车换行 */
|
||||
public void println() throws IOException
|
||||
{
|
||||
output.write(_CRLF_);
|
||||
}
|
||||
|
||||
/** 写内容,无回车换行 */
|
||||
public void print(String str) throws IOException
|
||||
{
|
||||
output.write(str.getBytes(characterEncoding));
|
||||
}
|
||||
|
||||
/** 清理内容 */
|
||||
public void clear()
|
||||
{
|
||||
output.reset();
|
||||
}
|
||||
|
||||
/** 刷新流(分块) */
|
||||
public void flush() throws IOException
|
||||
{
|
||||
if (isCommitted())
|
||||
return;
|
||||
|
||||
output.flush();
|
||||
}
|
||||
|
||||
public byte[] buildChunkedHeader(boolean chunked)
|
||||
{
|
||||
//1.1 写入标志
|
||||
if (chunked)
|
||||
{//分块
|
||||
setHeader(_TRANSFER_ENCODING_, _CHUNKED_);
|
||||
}
|
||||
else
|
||||
{//整块
|
||||
if (isResponseGZip() && output.getContentLength() > 256)
|
||||
{//如果支持gzip且内容长度大于256,则尝试压缩,压缩成功设置gzip头
|
||||
if (output.processGZipCompress())
|
||||
addHeader(_CONTENT_ENCODING_, _ENCODING_GZIP_);
|
||||
}
|
||||
|
||||
//整块的不管用户是否设置了内容长度,统一重设
|
||||
setHeader(_CONTENT_LENGTH_, output.getContentLength());
|
||||
}
|
||||
|
||||
if (!hasHeader(_CONTENT_TYPE_))
|
||||
{//1.2 没有contentType设置成默认格式
|
||||
setContentType(_TEXT_HTML_UTF_8_);
|
||||
}
|
||||
|
||||
//2.1 准备消息头
|
||||
StringBuilder strb = new StringBuilder();
|
||||
strb.append(version).append(" ").append(status).append(" ").append(Urls.encodeUTF8(reason)).append(_BR_);
|
||||
|
||||
for (Entry<String, String> entry : headers.entrySet())
|
||||
{//2.2 响应消息头
|
||||
strb.append(entry.getKey()).append(_COLON_).append(entry.getValue()).append(_BR_);
|
||||
}
|
||||
|
||||
//2.3 响应复杂的消息头
|
||||
strb.append(headerBuffer);
|
||||
|
||||
//2.4 增加时间和结束标志
|
||||
strb.append(_DATE_).append(_COLON_).append(DateTimes.getDateTimeHttp()).append(_BR_);
|
||||
strb.append(_BR_);//头部结束标志
|
||||
|
||||
return strb.toString().getBytes(_UTF_8_C_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
// toString & destroy
|
||||
/***********************************************************************/
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder strb = new StringBuilder();
|
||||
strb.append(version).append(" ").append(status).append(" ").append(Urls.encode(reason, characterEncoding)).append(_BR_);
|
||||
if (headers != null)
|
||||
{
|
||||
for (Entry<String, String> entry : headers.entrySet())
|
||||
{
|
||||
strb.append(entry.getKey()).append(_COLON_).append(entry.getValue()).append(_BR_);
|
||||
}
|
||||
}
|
||||
|
||||
if (headerBuffer != null)
|
||||
{
|
||||
strb.append(headerBuffer.toString());
|
||||
}
|
||||
strb.append(_BR_);
|
||||
return strb.toString();
|
||||
}
|
||||
|
||||
/** 销毁 */
|
||||
public void destroy()
|
||||
{
|
||||
if (headers != null)
|
||||
{
|
||||
headers.clear();
|
||||
headers = null;
|
||||
}
|
||||
|
||||
if (headerBuffer != null)
|
||||
{
|
||||
headerBuffer.setLength(0);
|
||||
headerBuffer = null;
|
||||
}
|
||||
|
||||
//引用置空
|
||||
output = null;
|
||||
header = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.zhiqim.httpd.bio.HttpBioListener;
|
||||
import org.zhiqim.httpd.bio.HttpBioSslListener;
|
||||
import org.zhiqim.httpd.nio.HttpNioListener;
|
||||
import org.zhiqim.httpd.nio.HttpNioSslListener;
|
||||
import org.zhiqim.kernel.Global;
|
||||
import org.zhiqim.kernel.Servicer;
|
||||
import org.zhiqim.kernel.config.Group;
|
||||
import org.zhiqim.kernel.extend.HashSetS;
|
||||
import org.zhiqim.kernel.logging.Log;
|
||||
import org.zhiqim.kernel.logging.LogFactory;
|
||||
import org.zhiqim.kernel.util.Arrays;
|
||||
import org.zhiqim.kernel.util.Asserts;
|
||||
import org.zhiqim.kernel.util.Classes;
|
||||
import org.zhiqim.kernel.util.Validates;
|
||||
|
||||
/**
|
||||
* HTTP多例服务,负责启动和关闭: <br><br>
|
||||
* 1、初始化AIO/BIO/NIO监听服务<br>
|
||||
* 2、加载和配置上下文环境 <br>
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public class HttpServer extends Servicer implements HttpdConstants
|
||||
{
|
||||
private static final Log log = LogFactory.getLog(HttpServer.class);
|
||||
|
||||
private boolean isRunning; //是否运行
|
||||
private HttpListener listener; //HTTP监听器
|
||||
private final List<HttpContext> contextList; //HTTP上下文环境表
|
||||
|
||||
/*********************************************************************************/
|
||||
//配置创建HTTP服务
|
||||
/*********************************************************************************/
|
||||
|
||||
public HttpServer()
|
||||
{
|
||||
this.contextList = new ArrayList<>();
|
||||
}
|
||||
|
||||
public boolean isRunning()
|
||||
{
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean create() throws Exception
|
||||
{
|
||||
//1.诊断参数
|
||||
Group group = Global.getGroup(id);
|
||||
Asserts.as(group != null?null:"HTTP服务[%s]未找到整个配置组", id);
|
||||
log.info("初始化[HTTP服务:%s]开始...", id);
|
||||
|
||||
//2、初始化上下文环境
|
||||
String contexts = group.getString(_SERVER_CONTEXT_);
|
||||
Asserts.as(Validates.isNotEmptyBlank(contexts)?null:"HTTP服务["+id+"]未找到[context]配置项");
|
||||
|
||||
//3、初始化监听器
|
||||
String scheme = group.getString(_LISTEN_SCHEME_, _HTTP_);
|
||||
String io = group.getString(_LISTEN_IO_, _BIO_);
|
||||
if (_HTTPS_.equalsIgnoreCase(scheme))
|
||||
{
|
||||
if (_NIO_.equalsIgnoreCase(io))
|
||||
listener = new HttpNioSslListener(this);
|
||||
else
|
||||
listener = new HttpBioSslListener(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_NIO_.equalsIgnoreCase(io))
|
||||
listener = new HttpNioListener(this);
|
||||
else
|
||||
listener = new HttpBioListener(this);
|
||||
}
|
||||
|
||||
listener.setGroup(group);
|
||||
listener.open();
|
||||
|
||||
//4、初始化上下文环境
|
||||
String[] contextArr = Arrays.toStringArray(contexts);
|
||||
for (String contextId : contextArr)
|
||||
{
|
||||
Group cGroup = Global.getGroup(contextId);
|
||||
Asserts.as(cGroup != null?null:"HTTP服务["+id+"]未找到context["+contextId+"]配置项");
|
||||
|
||||
String contextClass = cGroup.getString(_CONTEXT_CLASS_, _HTTP_CONTEXT_CLASS_);
|
||||
Object obj = Classes.newInstance(contextClass);
|
||||
Asserts.as((obj instanceof HttpContext)?null:"HTTP服务["+id+"]context["+contextId+"]的[class]配置项未实现HttpContext接口");
|
||||
|
||||
HttpContext context = (HttpContext)obj;
|
||||
context.setServer(this);
|
||||
if (!context.create(cGroup))
|
||||
return false;
|
||||
|
||||
contextList.add(context);
|
||||
}
|
||||
|
||||
isRunning = true;
|
||||
|
||||
log.info("初始化[HTTP服务:%s]"+this.listener.toString()+"完成!!!%s", id, _BR_);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception
|
||||
{
|
||||
isRunning = false;
|
||||
if (listener != null)
|
||||
{
|
||||
listener.close();
|
||||
listener = null;
|
||||
}
|
||||
|
||||
for (HttpContext context : contextList)
|
||||
{
|
||||
if (context.isRunning())
|
||||
context.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************************************/
|
||||
//手动创建服务 设置三个参数 domain & host & encoding 和 设置 listen & context 再setRunning()
|
||||
/***************************************************************************************************/
|
||||
|
||||
public void setRunning()
|
||||
{
|
||||
this.isRunning = true;
|
||||
}
|
||||
|
||||
public void addContext(HttpContext context)
|
||||
{
|
||||
//检查是否有相同的配置
|
||||
context.setServer(this);
|
||||
chkContextDomainPath(context.getContextDomains(), context.getContextPath());
|
||||
|
||||
//通过后放置到列表中
|
||||
contextList.add(context);
|
||||
}
|
||||
|
||||
public void removeContext(HttpContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
context.destroy();
|
||||
contextList.remove(context);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.error("移除上下文环境时异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeContext(String contextId)
|
||||
{
|
||||
HttpContext context = getContext(contextId);
|
||||
if (context == null)
|
||||
return;
|
||||
|
||||
removeContext(context);
|
||||
}
|
||||
|
||||
/** 检查域名和路径是否存在相同的配置 */
|
||||
public void chkContextDomainPath(HashSetS domains, String path)
|
||||
{
|
||||
if (domains.isEmpty())
|
||||
{//未配置域名
|
||||
for (HttpContext ctx : contextList)
|
||||
{
|
||||
if (!ctx.getContextDomains().isEmpty())
|
||||
continue;
|
||||
|
||||
if (!ctx.getContextPath().equals(path))
|
||||
continue;
|
||||
|
||||
throw Asserts.exception("存在相同的上下文环境配置[%s]", ctx.getContextPath());
|
||||
}
|
||||
}
|
||||
else
|
||||
{//有配置域名
|
||||
for (HttpContext ctx : contextList)
|
||||
{
|
||||
HashSetS ds = ctx.getContextDomains();
|
||||
if (ds.isEmpty())
|
||||
continue;
|
||||
|
||||
if (!ctx.getContextPath().equals(path))
|
||||
continue;
|
||||
|
||||
for (String d : domains.instance())
|
||||
{
|
||||
if (!ds.contains(d))
|
||||
continue;
|
||||
|
||||
//只要有一个成立则表示有相同
|
||||
throw Asserts.exception("存在相同的上下文环境配置[%s][%s]", d, ctx.getContextPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************************/
|
||||
//获取 & 配对 listen, context, scheme, port, domain, host, encoding
|
||||
/*********************************************************************************/
|
||||
|
||||
public HttpListener getListener()
|
||||
{
|
||||
return listener;
|
||||
}
|
||||
|
||||
public List<HttpContext> getContextList()
|
||||
{
|
||||
return contextList;
|
||||
}
|
||||
|
||||
public HttpContext getContext(String contextId)
|
||||
{
|
||||
Asserts.as(contextId != null?null:"上下文环境路径不能为空");
|
||||
|
||||
for (HttpContext context : contextList)
|
||||
{
|
||||
if (contextId.equals(context.getId()))
|
||||
return context;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public HttpContext getContext(String contextDomain, String contextPath)
|
||||
{
|
||||
Asserts.as(contextPath != null?null:"上下文环境路径不能为空");
|
||||
|
||||
if (!Validates.isEmptyBlank(contextDomain))
|
||||
{//1.域名不为空,优先找匹配上的
|
||||
for (HttpContext context : contextList)
|
||||
{
|
||||
HashSetS domains = context.getContextDomains();
|
||||
if (domains.isEmpty())
|
||||
continue;
|
||||
|
||||
if (domains.contains(contextDomain) && contextPath.equals(context.getContextPath()))
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
||||
//2.再找缺省未配置域名的,只比较上下文环境路径
|
||||
for (HttpContext context : contextList)
|
||||
{
|
||||
if (!context.getContextDomains().isEmpty())
|
||||
continue;
|
||||
|
||||
if (contextPath.equals(context.getContextPath()))
|
||||
return context;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getPort()
|
||||
{
|
||||
return listener.getPort();
|
||||
}
|
||||
|
||||
public String getScheme()
|
||||
{
|
||||
return listener.getScheme();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import org.zhiqim.kernel.extend.HashMapSO;
|
||||
|
||||
/**
|
||||
* HTTP会话接口定义
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2016-7-15 新建与整理
|
||||
*/
|
||||
public interface HttpSession
|
||||
{
|
||||
/************************************************************************************/
|
||||
//会话参数初始设置(IP地址 & 用户代理)
|
||||
/************************************************************************************/
|
||||
|
||||
public void setSessionIp(String sessionIp);
|
||||
|
||||
public void setUserAgent(String userAgent);
|
||||
|
||||
/************************************************************************************/
|
||||
//会话更新 & 失效
|
||||
/************************************************************************************/
|
||||
|
||||
public void updateLastAccessed();
|
||||
|
||||
public void updateInfo(String sessionIp, String userAgent);
|
||||
|
||||
public void invalidate();
|
||||
|
||||
/************************************************************************************/
|
||||
//用于业务浸入式更改sessionId(注:谨慎使用),HttpResponse会oldSessionId进行处理
|
||||
/************************************************************************************/
|
||||
|
||||
public void setNewSessionId(String newSessionId);
|
||||
|
||||
public String getOldSessionId();
|
||||
|
||||
public void clearOldSessionId();
|
||||
|
||||
/************************************************************************************/
|
||||
//获取参数判断值
|
||||
/************************************************************************************/
|
||||
|
||||
public HttpContext getContext();
|
||||
|
||||
public String getId();
|
||||
|
||||
public boolean isNew();
|
||||
|
||||
public String getSessionIp();
|
||||
|
||||
public String getUserAgent();
|
||||
|
||||
public int getMaxInactiveInterval();
|
||||
|
||||
public long getCreated();
|
||||
|
||||
public String getCreateTime();
|
||||
|
||||
public long getLastAccessed();
|
||||
|
||||
public String getLastAccessTime();
|
||||
|
||||
public long getRemainSecond();
|
||||
|
||||
public long getRemainMinute();
|
||||
|
||||
public long[] getRemainTime();
|
||||
|
||||
public String getRemainTimeDesc();
|
||||
|
||||
/**********************************************/
|
||||
//读写关联到HttpSession中attribute列表
|
||||
/**********************************************/
|
||||
|
||||
public HashMapSO getAttributes();
|
||||
|
||||
public Object getAttribute(String name);
|
||||
|
||||
public Object removeAttribute(String name);
|
||||
|
||||
public void setAttribute(String name, Object value);
|
||||
|
||||
public boolean hasAttribute(String name);
|
||||
|
||||
public Object getAttribute(String name, Object defaultValue);
|
||||
|
||||
public String getAttributeString(String name);
|
||||
|
||||
public String getAttributeString(String name, String defaultValue);
|
||||
|
||||
public int getAttributeInt(String name);
|
||||
|
||||
public int getAttributeInt(String name, int defaultValue);
|
||||
|
||||
public long getAttributeLong(String name);
|
||||
|
||||
public long getAttributeLong(String name, long defaultValue);
|
||||
|
||||
public boolean getAttributeBoolean(String name, boolean defaultValue);
|
||||
|
||||
/**********************************************/
|
||||
//SessionUser相关
|
||||
/**********************************************/
|
||||
|
||||
/** 判断会话中是否有用户信息 */
|
||||
public boolean hasSessionUser();
|
||||
|
||||
/** 获取会话用户信息中用户类,多个时抛异常 */
|
||||
public HttpSessionUser getSessionUser();
|
||||
|
||||
/** 获取会话用户名称,多个时抛异常 */
|
||||
public String getSessionName();
|
||||
|
||||
/** 绑定会话用户信息 */
|
||||
public void bindSessionUser(HttpSessionUser sessionUser);
|
||||
|
||||
/** 解绑会话用户信息 */
|
||||
public void unbindSessionUser();
|
||||
|
||||
/** 判断会话中是否有用户信息且指定的用户类 */
|
||||
public <T extends HttpSessionUser> boolean hasSessionUser(Class<T> clazz);
|
||||
|
||||
/** 获取会话用户信息且指定的用户类 */
|
||||
public <T extends HttpSessionUser> T getSessionUser(Class<T> clazz);
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.zhiqim.kernel.paging.PageResult;
|
||||
|
||||
/**
|
||||
* HTTP会话管理器接口<br><br>
|
||||
* 1.要求实现启动方法<br>
|
||||
* 2.设置会话值<br>
|
||||
* 3.获取会话值<br>
|
||||
* 4.删除会话值<br>
|
||||
* 5.遍历会话值
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public interface HttpSessionManager extends HttpdConstants
|
||||
{
|
||||
/** 设置上下文环境对象 */
|
||||
public void setContext(HttpContext context);
|
||||
|
||||
/** 获取上下文环境对象 */
|
||||
public HttpContext getContext();
|
||||
|
||||
/******************************************************************************************/
|
||||
//开启和关闭
|
||||
/******************************************************************************************/
|
||||
|
||||
/** 开启会话管理 */
|
||||
public void open();
|
||||
|
||||
/** 关闭会话管理 */
|
||||
public void close();
|
||||
|
||||
/******************************************************************************************/
|
||||
//设置参数部分
|
||||
/******************************************************************************************/
|
||||
|
||||
/** 设置会话超时时长 */
|
||||
public void setSessionTimeout(int sessionTimeout);
|
||||
|
||||
/** 获取会话超时时长 */
|
||||
public int getSessionTimeout();
|
||||
|
||||
/** 设置会话编号名称 */
|
||||
public void setSessionIdName(String sessionCookieName);
|
||||
|
||||
/** 获取会话编号名称 */
|
||||
public String getSessionIdName();
|
||||
|
||||
/** 设置会话参数 */
|
||||
public void setSessionParameter(String sessionParameter);
|
||||
|
||||
/******************************************************************************************/
|
||||
//设置 & 获取 & 失效 会话
|
||||
/******************************************************************************************/
|
||||
|
||||
/** 新建会话 */
|
||||
public HttpSession newSession(String sessionId);
|
||||
|
||||
/** 设置会话 */
|
||||
public void setSession(HttpSession session);
|
||||
|
||||
/** 获取会话 */
|
||||
public HttpSession getSession(String sessionId);
|
||||
|
||||
/** 判断会话是否存在 */
|
||||
public boolean hasSession(String sessionId);
|
||||
|
||||
/** 通过会话编号使会话失效 */
|
||||
public void invalidateSession(String sessionId);
|
||||
|
||||
/** 更新会话最后访问时间 */
|
||||
public void updateLastAccessed(String sessionId);
|
||||
|
||||
/** 更新会话信息 */
|
||||
public void updateInfo(String sessionId, String sessionIp, String userAgent);
|
||||
|
||||
/******************************************************************************************/
|
||||
//会话查询和统计
|
||||
/******************************************************************************************/
|
||||
|
||||
/** 会话数 */
|
||||
public int size();
|
||||
|
||||
/** 获取会话列表 */
|
||||
public List<HttpSession> getSessionList();
|
||||
|
||||
/** 获取会话分页信息 */
|
||||
public PageResult<HttpSession> getSessionPage(int pageNo, int pageSize);
|
||||
|
||||
/******************************************************************************************/
|
||||
//会话用户查询和统计
|
||||
/******************************************************************************************/
|
||||
|
||||
/** 会话登录数 */
|
||||
public int sizeUser();
|
||||
|
||||
/** 是否有会话名称对应的会话 */
|
||||
public boolean hasSessionName(String sessionName);
|
||||
|
||||
/** 获取会话登录用户列表,指定会话用户类名(如前后端共用session管理器的情况) */
|
||||
public List<HttpSessionUser> getSessionUserList();
|
||||
|
||||
/** 获取会话登录用户分页信息,指定会话用户类名(如前后端共用session管理器的情况) */
|
||||
public PageResult<HttpSessionUser> getSessionUserPage(int pageNo, int pageSize);
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.zhiqim.kernel.Global;
|
||||
import org.zhiqim.kernel.extend.HashMapSO;
|
||||
import org.zhiqim.kernel.util.Asserts;
|
||||
import org.zhiqim.kernel.util.Classes;
|
||||
import org.zhiqim.kernel.util.Ints;
|
||||
import org.zhiqim.kernel.util.Longs;
|
||||
import org.zhiqim.kernel.util.Strings;
|
||||
import org.zhiqim.kernel.util.Types;
|
||||
|
||||
/**
|
||||
* HTTP在线用户定义,子类继承时,需设置到HttpSessionManager中
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public abstract class HttpSessionUser
|
||||
{
|
||||
protected transient HttpSession session;
|
||||
|
||||
//两个冗余的字段,用于生成JSON时可以通过字符串找到对应的类名和字段
|
||||
protected String className;
|
||||
protected String sessionName;
|
||||
|
||||
//通用的值表,和session中的attributeMap不同的是:
|
||||
//1.valueMap绑定sessionUser,解绑即失效
|
||||
//2.attributeMap可用在和sessionUser无关的地方
|
||||
protected HashMapSO valueMap = new HashMapSO();
|
||||
|
||||
public HttpSessionUser()
|
||||
{
|
||||
className = this.getClass().getName();
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
//要求子类强制实现的方法
|
||||
/**************************************************/
|
||||
|
||||
public abstract String getSessionName();
|
||||
|
||||
/**************************************************/
|
||||
//由HttpSession回调
|
||||
/**************************************************/
|
||||
|
||||
public void setSession(HttpSession session)
|
||||
{
|
||||
this.session = session;
|
||||
this.sessionName = getSessionName();
|
||||
}
|
||||
|
||||
/**************************************************/
|
||||
//获取HttpSession对象和相关属性
|
||||
/**************************************************/
|
||||
|
||||
public HttpSession getSession()
|
||||
{
|
||||
return session;
|
||||
}
|
||||
|
||||
public HttpContext getContext()
|
||||
{
|
||||
return session.getContext();
|
||||
}
|
||||
|
||||
public String getSessionId()
|
||||
{
|
||||
return session.getId();
|
||||
}
|
||||
|
||||
public boolean isNew()
|
||||
{
|
||||
return session.isNew();
|
||||
}
|
||||
|
||||
public String getSessionIp()
|
||||
{
|
||||
return session.getSessionIp();
|
||||
}
|
||||
|
||||
public String getUserAgent()
|
||||
{
|
||||
return session.getUserAgent();
|
||||
}
|
||||
|
||||
public long getCreated()
|
||||
{
|
||||
return session.getCreated();
|
||||
}
|
||||
|
||||
public String getCreateTime()
|
||||
{
|
||||
return session.getCreateTime();
|
||||
}
|
||||
|
||||
public long getLastAccessed()
|
||||
{
|
||||
return session.getLastAccessed();
|
||||
}
|
||||
|
||||
public String getLastAccessTime()
|
||||
{
|
||||
return session.getLastAccessTime();
|
||||
}
|
||||
|
||||
public long getRemainSecond()
|
||||
{
|
||||
return session.getRemainSecond();
|
||||
}
|
||||
|
||||
public long getRemainMinute()
|
||||
{
|
||||
return session.getRemainMinute();
|
||||
}
|
||||
|
||||
public long[] getRemainTime()
|
||||
{
|
||||
return session.getRemainTime();
|
||||
}
|
||||
|
||||
public String getRemainTimeDesc()
|
||||
{
|
||||
return session.getRemainTimeDesc();
|
||||
}
|
||||
|
||||
/**********************************************/
|
||||
//读写关联到HttpSession中attribute列表
|
||||
/**********************************************/
|
||||
|
||||
public HashMapSO getAttributes()
|
||||
{
|
||||
return session.getAttributes();
|
||||
}
|
||||
|
||||
public Object getAttribute(String name)
|
||||
{
|
||||
return session.getAttribute(name);
|
||||
}
|
||||
|
||||
public Object removeAttribute(String name)
|
||||
{
|
||||
return session.removeAttribute(name);
|
||||
}
|
||||
|
||||
public void setAttribute(String name, Object value)
|
||||
{
|
||||
session.setAttribute(name, value);
|
||||
}
|
||||
|
||||
public boolean hasAttribute(String name)
|
||||
{
|
||||
return session.hasAttribute(name);
|
||||
}
|
||||
|
||||
/**********************************************/
|
||||
//读写关联到HttpSessionUser自己的参数列表
|
||||
/**********************************************/
|
||||
|
||||
public HashMapSO getValues()
|
||||
{
|
||||
return valueMap;
|
||||
}
|
||||
|
||||
public Object getValue(String key)
|
||||
{
|
||||
return valueMap.get(key);
|
||||
}
|
||||
|
||||
public boolean hasValue(String key)
|
||||
{
|
||||
return valueMap.containsKey(key);
|
||||
}
|
||||
|
||||
public Object removeValue(String key)
|
||||
{
|
||||
return valueMap.remove(key);
|
||||
}
|
||||
|
||||
public void setValue(String key, Object value)
|
||||
{
|
||||
valueMap.put(key, value);
|
||||
}
|
||||
|
||||
public void setValueTrue(String key)
|
||||
{
|
||||
valueMap.put(key, true);
|
||||
}
|
||||
|
||||
public void setValueFalse(String key)
|
||||
{
|
||||
valueMap.put(key, false);
|
||||
}
|
||||
|
||||
public String getValueString(String key)
|
||||
{
|
||||
return getValueString(key, null);
|
||||
}
|
||||
|
||||
public String getValueString(String key, String defaultValue)
|
||||
{
|
||||
Object value = getValue(key);
|
||||
return (value == null)?defaultValue:Strings.trim(String.valueOf(value));
|
||||
}
|
||||
|
||||
public int getValueInt(String key)
|
||||
{
|
||||
return getValueInt(key, -1);
|
||||
}
|
||||
|
||||
public int getValueInt(String key, int defaultValue)
|
||||
{
|
||||
return Ints.toInt(valueMap.get(key), defaultValue);
|
||||
}
|
||||
|
||||
public long getValueLong(String key)
|
||||
{
|
||||
return getValueLong(key, -1);
|
||||
}
|
||||
|
||||
public long getValueLong(String key, long defaultValue)
|
||||
{
|
||||
return Longs.toLong(valueMap.get(key), defaultValue);
|
||||
}
|
||||
|
||||
public boolean getValueBoolean(String key, boolean defaultValue)
|
||||
{
|
||||
Object value = valueMap.get(key);
|
||||
if (value == null)
|
||||
return defaultValue;
|
||||
else if (value instanceof Boolean)
|
||||
return (Boolean)value;
|
||||
else if (value instanceof String)
|
||||
return Boolean.parseBoolean((String)value);
|
||||
else
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 有条件判断是否有值,如果valueMap有值则返回valueMap中的true/false,如果没有,则通过类和静态方法名,返回true/false
|
||||
* 注意:1.如果valueMap中有值,值不是boolean类型,返回false
|
||||
* 2.如果类和静态方法返回值不是boolean类型,返回false,如果不是静态方法或静态方法参数不是HttpSessionUser返回false
|
||||
*
|
||||
* @param key 键值
|
||||
* @param className 类名
|
||||
* @param methodName 方法名,方法必须是静态方法,且参数为HttpSessionUser实例,如public static boolean isOpen(HttpSessionUser sessionUser){};
|
||||
* @return =true/false
|
||||
*/
|
||||
public boolean isValue(String key, String className, String staticMethodName)
|
||||
{
|
||||
if (hasValue(key))
|
||||
{//有值则取值
|
||||
Object value = getValue(key);
|
||||
return Types.isBoolean(value)?(Boolean)value:false;
|
||||
}
|
||||
|
||||
Class<?> clazz = Global.forName(className);
|
||||
Asserts.as(clazz != null?null:"判断会话属性值时,传入的类名或类别名不正确");
|
||||
|
||||
Method method = Classes.getMethodDeep(clazz, staticMethodName, this.getClass());
|
||||
Asserts.as(method != null?null:"判断会话属性值时,传入的静态方法名未找到");
|
||||
Asserts.as(Classes.isStaticMethod(method)?null:"判断会话属性值时,传入的方法名不是静态方法");
|
||||
|
||||
try
|
||||
{
|
||||
Object value = method.invoke(null, this);
|
||||
Asserts.as(Types.isBoolean(value)?null:"判断会话属性值时,方法返回的值不是boolean型");
|
||||
|
||||
return (Boolean)value;
|
||||
}
|
||||
catch (Exception e)
|
||||
{//异常返回false,表示业务处理失败
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.KeyStore;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLEngineResult;
|
||||
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
|
||||
import org.zhiqim.httpd.nio.HttpNioSslConnection;
|
||||
import org.zhiqim.kernel.config.Group;
|
||||
import org.zhiqim.kernel.util.Asserts;
|
||||
import org.zhiqim.kernel.util.Validates;
|
||||
|
||||
/**
|
||||
* SSL参数配置和管理
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2018-6-30 新建与整理
|
||||
*/
|
||||
public class HttpSslConfig implements HttpdConstants
|
||||
{
|
||||
//两项必须(服务端公私钥)
|
||||
private String keystorePath; // = "./conf/keystore.jks";
|
||||
private String keystorePass; // = "123456";
|
||||
|
||||
//三项根据要求可选(CA信任公钥)
|
||||
private String truststorePath; // = "./conf/truststore.jks";
|
||||
private String truststorePass; // = "123456";
|
||||
private boolean clientAuth; //是否需要客户端证验证(双向验证,客户端也要导入证书才行)
|
||||
|
||||
public void initParam(Group group)
|
||||
{
|
||||
//1.SSL参数(五项,其中Keystore两项必须)
|
||||
keystorePath = group.getString(_KEY_STORE_PATH_);
|
||||
keystorePass = group.getString(_KEY_STORE_PASS_);
|
||||
|
||||
Asserts.as(Validates.isNotEmpty(keystorePath)?null:"配置HTTPS时要求必须配置[keystorePath]不能为空");
|
||||
Asserts.as(Validates.isNotEmpty(keystorePass)?null:"配置HTTPS时要求必须配置[keystorePass]不能为空");
|
||||
|
||||
truststorePath = group.getString(_TRUST_STORE_PATH_);
|
||||
truststorePass = group.getString(_TRUST_STORE_PASS_);
|
||||
|
||||
Asserts.as((Validates.isNotEmpty(truststorePath)?Validates.isNotEmpty(truststorePass):true)?null:"配置HTTPS时如要配置了[truststorePath]则[truststorePass]不能为空");
|
||||
|
||||
clientAuth = group.isTrue(_CLIENT_AUTH_);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
//获取SSL创建的SSLContext&SSLServerSocketFactory
|
||||
/******************************************************************************/
|
||||
|
||||
/** 创建SSL工厂 */
|
||||
public SSLServerSocketFactory createFactory() throws Exception
|
||||
{
|
||||
return createSSLContext().getServerSocketFactory();
|
||||
}
|
||||
|
||||
/** 创建SSL环境 */
|
||||
public SSLContext createSSLContext() throws Exception
|
||||
{
|
||||
SSLContext sslContext = SSLContext.getInstance(SSL_PROTOCOL);
|
||||
|
||||
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(SSL_ALGORITHM);
|
||||
KeyStore keyStore = KeyStore.getInstance(SSL_KEYSTORE_TYPE);
|
||||
|
||||
FileInputStream kfis = new FileInputStream(keystorePath);
|
||||
keyStore.load(kfis, keystorePass.toCharArray());
|
||||
keyManagerFactory.init(keyStore, keystorePass.toCharArray());
|
||||
|
||||
TrustManager[] trustManager = null;
|
||||
if (Validates.isNotEmptyBlank(truststorePath))
|
||||
{//有CA信任证书的创建管理器
|
||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(SSL_ALGORITHM);
|
||||
KeyStore trustStore = KeyStore.getInstance(SSL_KEYSTORE_TYPE);
|
||||
FileInputStream tfis = new FileInputStream(truststorePath);
|
||||
trustStore.load(tfis, truststorePass.toCharArray());
|
||||
trustManagerFactory.init(trustStore);
|
||||
|
||||
trustManager = trustManagerFactory.getTrustManagers();
|
||||
}
|
||||
|
||||
sslContext.init(keyManagerFactory.getKeyManagers(), trustManager, new SecureRandom());
|
||||
return sslContext;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
//SSL握手
|
||||
/******************************************************************************/
|
||||
|
||||
/** 握手操作 */
|
||||
public boolean doHandshake(HttpNioSslConnection conn)
|
||||
{
|
||||
//1.初始化参数
|
||||
SSLEngine sslEngine = conn.getSSLEngine();
|
||||
|
||||
SSLSession session = sslEngine.getSession();
|
||||
int appBufMax = session.getApplicationBufferSize();
|
||||
int netBufMax = session.getPacketBufferSize();
|
||||
|
||||
ByteBuffer appBuf = ByteBuffer.allocate(appBufMax + 10);
|
||||
ByteBuffer netBuf = ByteBuffer.allocate(netBufMax);
|
||||
|
||||
try
|
||||
{
|
||||
//2.开启握手
|
||||
sslEngine.beginHandshake();
|
||||
|
||||
//3.握手执行
|
||||
return doHandshake(conn, sslEngine, appBuf, netBuf);
|
||||
}
|
||||
catch(Exception e)
|
||||
{//4.握手异常
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** 握手执行 */
|
||||
private boolean doHandshake(HttpNioSslConnection conn, SSLEngine sslEngine, ByteBuffer appBuf, ByteBuffer netBuf) throws IOException
|
||||
{
|
||||
HandshakeStatus hsStatus = sslEngine.getHandshakeStatus();
|
||||
|
||||
boolean handshakeDone = false;
|
||||
while (!handshakeDone)
|
||||
{
|
||||
switch (hsStatus)
|
||||
{
|
||||
case NEED_UNWRAP:
|
||||
{//1.客户端请求Hello
|
||||
netBuf.clear();
|
||||
conn.read(netBuf);
|
||||
netBuf.flip();
|
||||
|
||||
do
|
||||
{
|
||||
sslEngine.unwrap(netBuf, appBuf);
|
||||
hsStatus = doTask(sslEngine);
|
||||
}
|
||||
while(netBuf.hasRemaining() && hsStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP);
|
||||
break;
|
||||
}
|
||||
case NEED_WRAP:
|
||||
{//2.服务端响应Hello
|
||||
netBuf.clear();
|
||||
sslEngine.wrap(_HELLO_N_, netBuf);
|
||||
netBuf.flip();
|
||||
|
||||
conn.write(netBuf);
|
||||
hsStatus = doTask(sslEngine);
|
||||
break;
|
||||
}
|
||||
case NEED_TASK:
|
||||
{//3.等待任务,当前使用同步处理
|
||||
hsStatus = doTask(sslEngine);
|
||||
break;
|
||||
}
|
||||
case NOT_HANDSHAKING:
|
||||
{//4.握手成功
|
||||
handshakeDone = true;
|
||||
break;
|
||||
}
|
||||
case FINISHED:
|
||||
{//5.握手完成
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return handshakeDone;
|
||||
}
|
||||
|
||||
/** 握手任务 */
|
||||
private HandshakeStatus doTask(SSLEngine sslEngine)
|
||||
{
|
||||
Runnable task;
|
||||
while ((task = sslEngine.getDelegatedTask()) != null)
|
||||
{
|
||||
task.run();
|
||||
}
|
||||
|
||||
return sslEngine.getHandshakeStatus();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
//获取配置参数值
|
||||
/******************************************************************************/
|
||||
|
||||
public String getKeystorePath()
|
||||
{
|
||||
return keystorePath;
|
||||
}
|
||||
|
||||
public String getKeystorePass()
|
||||
{
|
||||
return keystorePass;
|
||||
}
|
||||
|
||||
public String getTruststorePath()
|
||||
{
|
||||
return truststorePath;
|
||||
}
|
||||
|
||||
public String getTruststorePass()
|
||||
{
|
||||
return truststorePass;
|
||||
}
|
||||
|
||||
public boolean isClientAuth()
|
||||
{
|
||||
return clientAuth;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
/**
|
||||
* SSL连接接口定义
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2018-7-6 新建与整理
|
||||
*/
|
||||
public interface HttpSslConnection extends HttpConnection
|
||||
{
|
||||
public SSLEngine getSSLEngine();
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.zhiqim.kernel.util.Files;
|
||||
import org.zhiqim.kernel.util.Streams;
|
||||
import org.zhiqim.kernel.util.Strings;
|
||||
import org.zhiqim.kernel.util.Validates;
|
||||
|
||||
/**
|
||||
* HTTP 上传类
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public class HttpUploader implements HttpdConstants, AutoCloseable
|
||||
{
|
||||
private static final String CONTENT_DISPOSITION = "Content-Disposition:";
|
||||
private static final String CONTENT_TYPE = "Content-Type:";
|
||||
|
||||
private HashMap<String, String> parameters;
|
||||
|
||||
private String name;
|
||||
private String fileContentType;
|
||||
private String fileName;
|
||||
private ByteArrayOutputStream fileContent;
|
||||
|
||||
public HttpUploader()
|
||||
{
|
||||
parameters = new HashMap<String, String>();
|
||||
fileContent = new ByteArrayOutputStream();
|
||||
}
|
||||
|
||||
public String getParameter(String name)
|
||||
{
|
||||
return parameters.get(name);
|
||||
}
|
||||
|
||||
public HashMap<String, String> getParameters()
|
||||
{
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getFileName()
|
||||
{
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public String getFileExt()
|
||||
{
|
||||
return Files.getFileExt(fileName);
|
||||
}
|
||||
|
||||
public String getFileContentType()
|
||||
{
|
||||
return fileContentType;
|
||||
}
|
||||
|
||||
public byte[] getBytes()
|
||||
{
|
||||
return fileContent.toByteArray();
|
||||
}
|
||||
|
||||
public int getFileSize()
|
||||
{
|
||||
return fileContent.size();
|
||||
}
|
||||
|
||||
public void writeTo(OutputStream out) throws IOException
|
||||
{
|
||||
fileContent.writeTo(out);
|
||||
}
|
||||
|
||||
public void writeToFile(String filePath) throws IOException
|
||||
{
|
||||
Files.write(filePath, fileContent.toByteArray());
|
||||
}
|
||||
|
||||
public InputStream getInputStream()
|
||||
{
|
||||
return new ByteArrayInputStream(fileContent.toByteArray());
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
try{fileContent.close();}catch (IOException e){}
|
||||
fileContent = null;
|
||||
}
|
||||
|
||||
public void parseHttpRequest(HttpRequest request, int maxSize) throws Exception
|
||||
{
|
||||
int contentLength = request.getContentLength();
|
||||
if (contentLength == 0)
|
||||
throw new Exception("非法的文件上传信息[contentLength == 0]");
|
||||
|
||||
if (contentLength > maxSize)
|
||||
throw new Exception("文件超过大小[contentLength == "+ contentLength +"]");
|
||||
|
||||
String contentType = request.getContentType();
|
||||
if (contentType == null)
|
||||
throw new Exception("非法的文件上传信息[contentType == null]");
|
||||
|
||||
if (!contentType.startsWith(_MULTIPART_FORM_DATA_))
|
||||
throw new Exception("非法的文件上传信息[contentType == "+ contentType +"]");
|
||||
|
||||
int ind = contentType.indexOf("boundary=");
|
||||
if (ind == -1)
|
||||
throw new Exception("非法的文件上传信息[contentType == "+ contentType +"]");
|
||||
|
||||
String boundary = contentType.substring(ind+"boundary=".length());
|
||||
byte[] buffer = new byte[4096];
|
||||
InputStream input = request.getInputStream();
|
||||
|
||||
int len = 0; String name = null;String curContentType = null;
|
||||
int type = 0; boolean isSkinEmptyLine = false;boolean isLastBR = false;
|
||||
while ((len = Streams.readLine(input, buffer, buffer.length)) != -1)
|
||||
{
|
||||
String line = new String(buffer, 0, len, request.getCharacterEncoding());
|
||||
if (line.startsWith("--"+boundary+"--"))
|
||||
{//全部内容结束
|
||||
break;
|
||||
}
|
||||
|
||||
if (line.startsWith("--"+boundary))
|
||||
{//新内容开始
|
||||
type = 0; //重置为未知
|
||||
isSkinEmptyLine = false;//重置下一行可以跳过空行
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isSkinEmptyLine && Validates.isEmptyBlank(line))
|
||||
{//跳过内容之前的空行
|
||||
isSkinEmptyLine = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Strings.startsWithIgnoreCase(line, CONTENT_DISPOSITION))
|
||||
{//内容配置开始,前面空行不处理
|
||||
String formData = line.substring(CONTENT_DISPOSITION.length()).trim();
|
||||
name = parseFormDataName(formData);
|
||||
if (name == null)
|
||||
{//无效的配置
|
||||
isSkinEmptyLine = false;//重置下一行可以跳过空行
|
||||
continue;
|
||||
}
|
||||
|
||||
String filename = parseFormDataFileName(formData);
|
||||
if (filename == null)
|
||||
{
|
||||
type = 1;//文本类型
|
||||
if (!parameters.containsKey(name))
|
||||
parameters.put(name, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
type = 2;//文件类型
|
||||
this.name = name;
|
||||
this.fileName = filename;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Strings.startsWithIgnoreCase(line, CONTENT_TYPE))
|
||||
{//内容类型开始,文本类型不一般会指定
|
||||
curContentType = line.substring(CONTENT_TYPE.length()).trim();
|
||||
if (type == 2)
|
||||
this.fileContentType = curContentType;
|
||||
|
||||
isSkinEmptyLine = false;//重置下一行可以跳过空行
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type == 1)
|
||||
{//文本参数,仅支持一行,多行表示该参数多个值,空行不处理
|
||||
parseFormValue(request, name, line);
|
||||
isSkinEmptyLine = false;//重置下一行可以跳过空行
|
||||
}
|
||||
else if (type == 2)
|
||||
{//文件内容
|
||||
if (isLastBR)
|
||||
{//上一个回车换行加上,如果不能到这里,表示上一个回车换行是结尾
|
||||
fileContent.write(_CRLF_);
|
||||
isLastBR = false;
|
||||
}
|
||||
|
||||
if (!line.endsWith(_BR_))
|
||||
fileContent.write(buffer, 0, len);
|
||||
else
|
||||
{//文件如果遇到\r\n,要下一个循环判断是否是结尾
|
||||
fileContent.write(buffer, 0, len-2);
|
||||
isLastBR = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{//未定位到文件还是文本时不处理,一般是多余的\r\n
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 解析form-data */
|
||||
private String parseFormDataName(String formData)
|
||||
{
|
||||
String key = "name=\"";
|
||||
int ind = formData.indexOf(key);
|
||||
if (ind == -1)
|
||||
return null;
|
||||
int ind2 = formData.indexOf("\"", ind+key.length());
|
||||
if (ind2 == -1)
|
||||
return null;
|
||||
|
||||
return formData.substring(ind+key.length(), ind2);
|
||||
}
|
||||
|
||||
/** 解析form-data */
|
||||
private String parseFormDataFileName(String formData)
|
||||
{
|
||||
String key = "filename=\"";
|
||||
int ind = formData.indexOf(key);
|
||||
if (ind == -1)
|
||||
return null;
|
||||
int ind2 = formData.indexOf("\"", ind+key.length());
|
||||
if (ind2 == -1)
|
||||
return null;
|
||||
|
||||
String name = formData.substring(ind+key.length(), ind2);
|
||||
return name;
|
||||
}
|
||||
|
||||
private void parseFormValue(HttpRequest request, String name, String line)
|
||||
{
|
||||
line = line.replaceAll("\r", "");
|
||||
line = line.replaceAll("\n", "");
|
||||
|
||||
String value = parameters.get(name);
|
||||
if (value == null)
|
||||
{
|
||||
parameters.put(name, line);
|
||||
request.setParameterOnCNT(name, line);
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters.put(name, value + "," + line);//参数名相同时,使用逗号隔开
|
||||
request.setParameterOnCNT(name, value + "," + line);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
|
||||
/**
|
||||
* HttpWebsocket接口定义
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2017-6-9 新建与整理
|
||||
*/
|
||||
public interface HttpWebsocket
|
||||
{
|
||||
/**
|
||||
* 接收到连接开启
|
||||
*
|
||||
* @param conn 消息连接
|
||||
*/
|
||||
public void onOpen(HttpWebsocketConnection conn);
|
||||
|
||||
/**
|
||||
* 接收连接主动关闭
|
||||
*
|
||||
* @param conn 消息连接
|
||||
*/
|
||||
public void onClose(HttpWebsocketConnection conn);
|
||||
|
||||
/**
|
||||
* 接收异常
|
||||
*
|
||||
* @param conn 消息连接
|
||||
* @param e 消息异常
|
||||
*/
|
||||
public void onException(HttpWebsocketConnection conn, Throwable e);
|
||||
|
||||
/**
|
||||
* 接收到文本消息
|
||||
*
|
||||
* @param conn 消息连接
|
||||
* @param message 消息字符串
|
||||
*/
|
||||
public void onMessage(HttpWebsocketConnection conn, String message);
|
||||
|
||||
/**
|
||||
* 接收到字节消息
|
||||
*
|
||||
* @param conn 消息连接
|
||||
* @param message 消息字节数组
|
||||
*/
|
||||
public void onMessage(HttpWebsocketConnection conn, byte[] message);
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import org.zhiqim.kernel.logging.Log;
|
||||
import org.zhiqim.kernel.logging.LogFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Websocket连接
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2018-5-29 新建与整理
|
||||
*/
|
||||
public interface HttpWebsocketConnection extends HttpdConstants
|
||||
{
|
||||
public Log log = LogFactory.getLog(HttpWebsocketConnection.class);
|
||||
|
||||
/***********************************************************************************/
|
||||
//打开&关闭
|
||||
/***********************************************************************************/
|
||||
|
||||
/** 启动 */
|
||||
public void open();
|
||||
|
||||
/** 关闭连接通知并删除 */
|
||||
public void close();
|
||||
|
||||
/** 异常连接通知并删除 */
|
||||
public void exception(Throwable e);
|
||||
|
||||
/***********************************************************************************/
|
||||
//发送数据
|
||||
/***********************************************************************************/
|
||||
|
||||
/** 发送PING消息 */
|
||||
public boolean sendPing();
|
||||
|
||||
/** 发送文本消息 */
|
||||
public boolean send(String text);
|
||||
|
||||
/** 发送字节数据 */
|
||||
public boolean send(byte[] data);
|
||||
|
||||
/***********************************************************************************/
|
||||
//获取属性
|
||||
/***********************************************************************************/
|
||||
|
||||
/** 获取协议 */
|
||||
public String getProtocol();
|
||||
|
||||
/** 获取会话管理器 */
|
||||
public HttpSessionManager getSessionManager();
|
||||
|
||||
/** 获取会话,再通过管理器获取会话对象 */
|
||||
public String getSessionId();
|
||||
|
||||
/** 获取会话信息 */
|
||||
public HttpSession getSession();
|
||||
|
||||
/** 获取Websocket管理器 */
|
||||
public HttpWebsocketManager getWebsocketManager();
|
||||
|
||||
/** 获取WebSocket对象 */
|
||||
public HttpWebsocket getWebsocket();
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Websocket连接抽象类
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2018-6-30 新建与整理
|
||||
*/
|
||||
public abstract class HttpWebsocketConnectionAbs implements HttpWebsocketConnection
|
||||
{
|
||||
protected HttpContext context;
|
||||
protected HttpWebsocketManager manager;
|
||||
protected String protocol;
|
||||
protected String sessionId;
|
||||
protected HttpWebsocket websocket;
|
||||
protected volatile boolean isRunning;
|
||||
|
||||
public HttpWebsocketConnectionAbs(HttpContext context, String protocol, String sessionId)
|
||||
{
|
||||
this.context = context;
|
||||
this.manager = context.getWebsocketManager();
|
||||
this.protocol = protocol;
|
||||
this.sessionId = sessionId;
|
||||
|
||||
this.websocket = manager.getWebsocket(protocol);
|
||||
if (this.websocket != null)
|
||||
{//开启回调
|
||||
this.websocket.onOpen(this);
|
||||
}
|
||||
}
|
||||
|
||||
/** 子类根据不同的结构提供不同的连接类 */
|
||||
public abstract HttpConnection getConnection();
|
||||
|
||||
/***********************************************************************************/
|
||||
//打开&关闭
|
||||
/***********************************************************************************/
|
||||
|
||||
@Override /** 开启,子类实现 */
|
||||
public abstract void open();
|
||||
|
||||
@Override /** 正常关闭 */
|
||||
public void close()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (websocket != null)
|
||||
websocket.onClose(this);
|
||||
}
|
||||
finally
|
||||
{
|
||||
websocket = null;
|
||||
getWebsocketManager().remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override /** 异常关闭 */
|
||||
public void exception(Throwable e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (websocket != null)
|
||||
websocket.onException(this, e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
websocket = null;
|
||||
getWebsocketManager().remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************/
|
||||
//发送数据
|
||||
/***********************************************************************************/
|
||||
|
||||
public boolean send(String text)
|
||||
{
|
||||
HttpConnection conn = getConnection();
|
||||
if (conn == null || conn.isClosed())
|
||||
return false;
|
||||
|
||||
HttpWebsocketMessage message = new HttpWebsocketMessage().build(text);
|
||||
return send(message.toBytes());
|
||||
}
|
||||
|
||||
public boolean sendPing()
|
||||
{
|
||||
HttpConnection conn = getConnection();
|
||||
if (conn == null || conn.isClosed())
|
||||
return false;
|
||||
|
||||
HttpWebsocketMessage message = new HttpWebsocketMessage().buildPing();
|
||||
return send(message.toBytes());
|
||||
}
|
||||
|
||||
public boolean send(byte[] data)
|
||||
{
|
||||
HttpConnection conn = getConnection();
|
||||
if (conn == null || conn.isClosed())
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
conn.write(data, 0, data.length);
|
||||
return true;
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
exception(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************************/
|
||||
//获取属性
|
||||
/***********************************************************************************/
|
||||
|
||||
public String getProtocol()
|
||||
{
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public HttpSessionManager getSessionManager()
|
||||
{
|
||||
return context.getSessionManager();
|
||||
}
|
||||
|
||||
public String getSessionId()
|
||||
{
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public HttpSession getSession()
|
||||
{
|
||||
return getSessionManager().getSession(sessionId);
|
||||
}
|
||||
|
||||
public HttpWebsocket getWebsocket()
|
||||
{
|
||||
return websocket;
|
||||
}
|
||||
|
||||
public HttpWebsocketManager getWebsocketManager()
|
||||
{
|
||||
return context.getWebsocketManager();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Websocket管理器定义
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2018-9-29 新建与整理
|
||||
*/
|
||||
public interface HttpWebsocketManager
|
||||
{
|
||||
/** 获取管理器对应的上下文环境 */
|
||||
public HttpContext getContext();
|
||||
|
||||
/********************************************************************/
|
||||
//开启和关闭
|
||||
/********************************************************************/
|
||||
|
||||
/** 开启管理 */
|
||||
public void open();
|
||||
|
||||
/** 关闭管理 */
|
||||
public void close();
|
||||
|
||||
/*********************************************************************/
|
||||
//增加&删除&获取
|
||||
/*********************************************************************/
|
||||
|
||||
/** 获取HttpWebsocket实现类 */
|
||||
public HttpWebsocket getWebsocket(String protocol);
|
||||
|
||||
/** 获取协议名下所有连接 */
|
||||
public List<HttpWebsocketConnection> get(String protocol);
|
||||
|
||||
/** 获取协议名下某个用户的所有连接 */
|
||||
public List<HttpWebsocketConnection> get(String protocol, String sessionId);
|
||||
|
||||
/** 由HttpWebsocketService增加连接关联到会话 */
|
||||
public void add(HttpWebsocketConnection conn);
|
||||
|
||||
/** 从连接中收到结束取消关联会话 */
|
||||
public void remove(HttpWebsocketConnection conn);
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.zhiqim.kernel.constants.CodeConstants;
|
||||
import org.zhiqim.kernel.util.Asserts;
|
||||
import org.zhiqim.kernel.util.Bytes;
|
||||
import org.zhiqim.kernel.util.Streams;
|
||||
import org.zhiqim.kernel.util.Strings;
|
||||
import org.zhiqim.kernel.util.mutables.MInt;
|
||||
|
||||
/**
|
||||
* HttpWebsocket数据格式:
|
||||
* 第一字节,第1位:FIN,标识是否为此消息的最后一个数据包
|
||||
* 第一字节,第5,6,7,8位,opcode,操作码(0-15):
|
||||
* 0x00:标识一个中间数据包
|
||||
* 0x01:标识一个text类型数据包
|
||||
* 0x02:标识一个binary类型数据包
|
||||
* 0x08:标识一个断开连接类型数据包
|
||||
* 0x09:标识一个ping类型数据包
|
||||
* 0x0A:表示一个pong类型数据包
|
||||
* 0x03-07:保留
|
||||
* 0x0B-0F:保留
|
||||
*
|
||||
* 0–999 保留段, 未使用.
|
||||
* 1000 CLOSE_NORMAL 正常关闭; 无论为何目的而创建, 该链接都已成功完成任务.
|
||||
* 1001 CLOSE_GOING_AWAY 终端离开, 可能因为服务端错误, 也可能因为浏览器正从打开连接的页面跳转离开.
|
||||
* 1002 CLOSE_PROTOCOL_ERROR 由于协议错误而中断连接.
|
||||
* 1003 CLOSE_UNSUPPORTED 由于接收到不允许的数据类型而断开连接 (如仅接收文本数据的终端接收到了二进制数据).
|
||||
* 1004 保留. 其意义可能会在未来定义.
|
||||
* 1005 CLOSE_NO_STATUS 保留. 表示没有收到预期的状态码.
|
||||
* 1006 CLOSE_ABNORMAL 保留. 用于期望收到状态码时连接非正常关闭 (也就是说, 没有发送关闭帧).
|
||||
* 1007 Unsupported Data 由于收到了格式不符的数据而断开连接 (如文本消息中包含了非 UTF-8 数据).
|
||||
* 1008 Policy Violation 由于收到不符合约定的数据而断开连接. 这是一个通用状态码, 用于不适合使用 1003 和 1009 状态码的场景.
|
||||
* 1009 CLOSE_TOO_LARGE 由于收到过大的数据帧而断开连接.
|
||||
* 1010 Missing Extension 客户端期望服务器商定一个或多个拓展, 但服务器没有处理, 因此客户端断开连接.
|
||||
* 1011 Internal Error 客户端由于遇到没有预料的情况阻止其完成请求, 因此服务端断开连接.
|
||||
* 1012 Service Restart 服务器由于重启而断开连接. [Ref]
|
||||
* 1013 Try Again Later 服务器由于临时原因断开连接, 如服务器过载因此断开一部分客户端连接. [Ref]
|
||||
* 1014 由 WebSocket 标准保留以便未来使用.
|
||||
* 1015 TLS Handshake 保留. 表示连接由于无法完成 TLS 握手而关闭 (例如无法验证服务器证书).
|
||||
* 1016–1999 由 WebSocket 标准保留以便未来使用.
|
||||
* 2000–2999 由 WebSocket 拓展保留使用.
|
||||
* 3000–3999 可以由库或框架使用. 不应由应用使用. 可以在 IANA 注册, 先到先得.
|
||||
* 4000–4999 可以由应用使用.
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2017-6-1 新建与整理
|
||||
*/
|
||||
public class HttpWebsocketMessage implements CodeConstants
|
||||
{
|
||||
protected boolean fin;
|
||||
protected int opcode;
|
||||
|
||||
protected boolean mask;
|
||||
protected byte[] masks;
|
||||
protected int length;
|
||||
protected byte[] content;
|
||||
|
||||
//内容解析属性:真实内容长度&内容文本
|
||||
protected int contentLen;
|
||||
protected String text;
|
||||
|
||||
public HttpWebsocketMessage parse(InputStream in) throws IOException
|
||||
{
|
||||
int first = in.read() & 0xFF;
|
||||
int second = in.read() & 0xFF;
|
||||
|
||||
//1.FIN
|
||||
this.fin = (first & 0x80) != 0;
|
||||
|
||||
//2.opcode
|
||||
this.opcode = first & 0x0F;
|
||||
|
||||
//3.MASK
|
||||
this.mask = (second & 0x80) != 0;
|
||||
|
||||
//4.length
|
||||
this.contentLen = this.length = second & 0x7F;
|
||||
if (this.length == 126)
|
||||
{//2字节表示长度
|
||||
byte[] buf = Streams.getBytes(in, 2);
|
||||
this.contentLen = Bytes.BU.getShortUnsigned(buf, 0);
|
||||
}
|
||||
else if (this.length == 127)
|
||||
{//8字节表示长度
|
||||
byte[] buf = Streams.getBytes(in, 8);
|
||||
long len = Bytes.BU.getLong(buf, 0);
|
||||
if (len > Integer.MAX_VALUE)
|
||||
throw Asserts.exception("超出支持的能力");
|
||||
|
||||
this.contentLen = (int)len;
|
||||
}
|
||||
|
||||
//5.masks
|
||||
if (mask)
|
||||
{//存在掩码的情况,取4字节
|
||||
this.masks = Streams.getBytes(in, 4);
|
||||
}
|
||||
|
||||
//6.内容
|
||||
if (contentLen > 0)
|
||||
{//有内容
|
||||
this.content = Streams.getBytes(in, contentLen);
|
||||
if (mask)
|
||||
{//存在掩码的情况,作处理
|
||||
for (int i=0;i<content.length;i++)
|
||||
{
|
||||
content[i] = (byte)(content[i] ^ masks[i % 4]);
|
||||
}
|
||||
}
|
||||
|
||||
if (isText())
|
||||
{//文本的解析成字符串
|
||||
text = Strings.newStringUTF8(content);
|
||||
}
|
||||
else if (isClose())
|
||||
{//结束符的有状态码,CloseEvent.code,如1001
|
||||
text = String.valueOf(Bytes.BU.getShortUnsigned(content, 0));
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpWebsocketMessage build(String text)
|
||||
{
|
||||
this.fin = true;
|
||||
this.opcode = 0x01;
|
||||
this.mask = false;
|
||||
|
||||
this.text = text;
|
||||
this.content = text.getBytes(_UTF_8_C_);
|
||||
this.contentLen = this.content.length;
|
||||
|
||||
//计算长度
|
||||
if (this.contentLen < 126)
|
||||
this.length = contentLen;
|
||||
else if (this.contentLen <= 65535)
|
||||
this.length = 126;
|
||||
else
|
||||
this.length = 127;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpWebsocketMessage buildPing()
|
||||
{
|
||||
this.fin = true;
|
||||
this.opcode = 0x09;
|
||||
this.mask = false;
|
||||
|
||||
this.text = null;
|
||||
this.content = null;
|
||||
this.contentLen = 0;
|
||||
|
||||
this.length = 0;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public HttpWebsocketMessage buildPong()
|
||||
{
|
||||
this.fin = true;
|
||||
this.opcode = 0x0A;
|
||||
this.mask = false;
|
||||
|
||||
this.text = null;
|
||||
this.content = null;
|
||||
this.contentLen = 0;
|
||||
|
||||
this.length = 0;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public byte[] toBytes()
|
||||
{//不加masks,长度=前两字节+可能的长度字节+内容
|
||||
int len = 2 + ((this.length == 126)?2:(this.length == 127)?8:0) + contentLen;
|
||||
byte[] buf = new byte[len];
|
||||
|
||||
buf[0] = (byte)(fin?(0x80 | opcode):opcode);
|
||||
buf[1] = (byte)this.length;
|
||||
|
||||
MInt off = new MInt(2);
|
||||
if (length == 126)
|
||||
Bytes.BU.putShort(buf, off, contentLen);
|
||||
else if (length == 127)
|
||||
Bytes.BU.putLong(buf, off, contentLen);
|
||||
|
||||
if (contentLen > 0)
|
||||
{//有内容
|
||||
Bytes.putBytes(buf, off, content);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
// 业务方法
|
||||
/***********************************************************************/
|
||||
|
||||
public boolean isText()
|
||||
{
|
||||
return opcode == 0x01;
|
||||
}
|
||||
|
||||
public boolean isBinary()
|
||||
{
|
||||
return opcode == 0x02;
|
||||
}
|
||||
|
||||
public boolean isClose()
|
||||
{
|
||||
return opcode == 0x08;
|
||||
}
|
||||
|
||||
public boolean isPing()
|
||||
{
|
||||
return opcode == 0x09;
|
||||
}
|
||||
|
||||
public boolean isPong()
|
||||
{
|
||||
return opcode == 0x0A;
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
// 获取&设置
|
||||
/***********************************************************************/
|
||||
|
||||
public boolean isFin()
|
||||
{
|
||||
return fin;
|
||||
}
|
||||
|
||||
public int getOpcode()
|
||||
{
|
||||
return opcode;
|
||||
}
|
||||
|
||||
public boolean isMask()
|
||||
{
|
||||
return mask;
|
||||
}
|
||||
|
||||
public byte[] getMasks()
|
||||
{
|
||||
return masks;
|
||||
}
|
||||
|
||||
public int getLength()
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
public String getText()
|
||||
{
|
||||
return text;
|
||||
}
|
||||
|
||||
public int getContentLen()
|
||||
{
|
||||
return contentLen;
|
||||
}
|
||||
|
||||
public byte[] getContent()
|
||||
{
|
||||
return (contentLen == 0)?new byte[0]:content;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.zhiqim.kernel.constants.CodeConstants;
|
||||
import org.zhiqim.kernel.util.Asserts;
|
||||
import org.zhiqim.kernel.util.Bytes;
|
||||
import org.zhiqim.kernel.util.Strings;
|
||||
|
||||
/**
|
||||
* HttpWebsocket数据格式:
|
||||
* 第一字节,第1位:FIN,标识是否为此消息的最后一个数据包
|
||||
* 第一字节,第5,6,7,8位,opcode,操作码(0-15):
|
||||
* 0x00:标识一个中间数据包
|
||||
* 0x01:标识一个text类型数据包
|
||||
* 0x02:标识一个binary类型数据包
|
||||
* 0x08:标识一个断开连接类型数据包
|
||||
* 0x09:标识一个ping类型数据包
|
||||
* 0x0A:表示一个pong类型数据包
|
||||
* 0x03-07:保留
|
||||
* 0x0B-0F:保留
|
||||
*
|
||||
* 一共分5步读取数据
|
||||
* 1、读first字节
|
||||
* 2、读second字节
|
||||
* 3、根据length读2字节或8字节
|
||||
* 4、读masks
|
||||
* 5、读length
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2017-6-1 新建与整理
|
||||
*/
|
||||
public class HttpWebsocketMessageAsync extends HttpWebsocketMessage implements CodeConstants
|
||||
{
|
||||
private int step;
|
||||
private int first;
|
||||
private int second;
|
||||
private byte[] buffer;
|
||||
private int bufferOffset;
|
||||
private int masksOffset;
|
||||
private int contentOffset;
|
||||
|
||||
public boolean parse(HttpInputStream in) throws IOException
|
||||
{
|
||||
if (step < 1)
|
||||
{//第一步
|
||||
first = in.read();
|
||||
if (first == -1)
|
||||
{//异步未读完,等待下次再读
|
||||
return false;
|
||||
}
|
||||
|
||||
step = 1;
|
||||
}
|
||||
|
||||
if (step < 2)
|
||||
{//第二步
|
||||
second = in.read();
|
||||
if (second == -1)
|
||||
{//异步未读完,等待下次再读
|
||||
return false;
|
||||
}
|
||||
|
||||
step = 2;
|
||||
}
|
||||
|
||||
//1.FIN
|
||||
fin = (first & 0x80) != 0;
|
||||
|
||||
//2.opcode
|
||||
opcode = first & 0x0F;
|
||||
|
||||
//3.MASK
|
||||
mask = (second & 0x80) != 0;
|
||||
|
||||
//4.length
|
||||
contentLen = length = second & 0x7F;
|
||||
if (length == 126)
|
||||
{
|
||||
if (step < 3)
|
||||
{
|
||||
if (buffer == null)
|
||||
{//初始化
|
||||
buffer = new byte[2];
|
||||
bufferOffset = 0;
|
||||
}
|
||||
|
||||
byte[] buf = in.read(2 - bufferOffset);
|
||||
if (buf != null && buf.length > 0)
|
||||
{
|
||||
bufferOffset = Bytes.putBytes(buffer, bufferOffset, buf);
|
||||
}
|
||||
|
||||
if (bufferOffset < 2)
|
||||
{//异步未读完,等待下次再读
|
||||
return false;
|
||||
}
|
||||
|
||||
contentLen = Bytes.BU.getShortUnsigned(buffer, 0);
|
||||
step = 3;
|
||||
}
|
||||
}
|
||||
else if (length == 127)
|
||||
{
|
||||
if (step < 3)
|
||||
{
|
||||
if (buffer == null)
|
||||
{//初始化
|
||||
buffer = new byte[8];
|
||||
bufferOffset = 0;
|
||||
}
|
||||
|
||||
byte[] buf = in.read(8 - bufferOffset);
|
||||
if (buf != null && buf.length > 0)
|
||||
{
|
||||
bufferOffset = Bytes.putBytes(buffer, bufferOffset, buf);
|
||||
}
|
||||
|
||||
if (bufferOffset < 8)
|
||||
{//异步未读完,等待下次再读
|
||||
return false;
|
||||
}
|
||||
|
||||
long len = Bytes.BU.getLong(buf, 0);
|
||||
if (len > Integer.MAX_VALUE)
|
||||
throw Asserts.exception("超出支持的能力");
|
||||
|
||||
contentLen = (int)len;
|
||||
step = 3;
|
||||
}
|
||||
}
|
||||
|
||||
//5.masks
|
||||
if (step < 4)
|
||||
{
|
||||
if (mask)
|
||||
{
|
||||
if (masks == null)
|
||||
{//初始化
|
||||
masks = new byte[4];
|
||||
masksOffset = 0;
|
||||
}
|
||||
|
||||
byte[] buf = in.read(4 - masksOffset);
|
||||
if (buf != null && buf.length > 0)
|
||||
{
|
||||
masksOffset = Bytes.putBytes(masks, masksOffset, buf);
|
||||
}
|
||||
|
||||
if (masksOffset < 4)
|
||||
{//异步未读完,等待下次再读
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
step = 4;
|
||||
}
|
||||
|
||||
//6.内容
|
||||
if (step < 5)
|
||||
{
|
||||
if (contentLen > 0)
|
||||
{//有内容
|
||||
if (content == null)
|
||||
{//初始化
|
||||
content = new byte[contentLen];
|
||||
contentOffset = 0;
|
||||
}
|
||||
|
||||
byte[] buf = in.read(contentLen - contentOffset);
|
||||
if (buf != null && buf.length > 0)
|
||||
{
|
||||
contentOffset = Bytes.putBytes(content, contentOffset, buf);
|
||||
}
|
||||
|
||||
if (contentOffset < contentLen)
|
||||
{//异步未读完,等待下次再读
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mask)
|
||||
{
|
||||
for (int i=0;i<content.length;i++)
|
||||
{
|
||||
content[i] = (byte)(content[i] ^ masks[i % 4]);
|
||||
}
|
||||
}
|
||||
|
||||
if (isText())
|
||||
{//文本的解析成字符串
|
||||
text = Strings.newStringUTF8(content);
|
||||
}
|
||||
else if (isClose())
|
||||
{//结束符的有状态码,CloseEvent.code,如1001
|
||||
text = String.valueOf(Bytes.BU.getShortUnsigned(content, 0));
|
||||
}
|
||||
}
|
||||
|
||||
step = 5;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
// 获取&设置
|
||||
/***********************************************************************/
|
||||
|
||||
public boolean isParsed()
|
||||
{
|
||||
return step == 5;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.zhiqim.kernel.util.codes.Base64;
|
||||
import org.zhiqim.kernel.util.codes.SHA1;
|
||||
|
||||
/**
|
||||
* HttpWebsocket服务
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2017-6-9 新建与整理
|
||||
*/
|
||||
public class HttpWebsocketService implements HttpExecutor
|
||||
{
|
||||
@Override
|
||||
public boolean isMatch(String pathInContext)
|
||||
{
|
||||
return _PATH_SERVICE_WS_.equals(pathInContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(HttpRequest request, HttpResponse response) throws IOException
|
||||
{
|
||||
if (!request.isWebSocket())
|
||||
{//非WS服务不支持
|
||||
response.sendError(_403_FORBIDDEN_);
|
||||
return;
|
||||
}
|
||||
|
||||
HttpSession session = request.getSession();
|
||||
if (session == null)
|
||||
{//必须会话支持
|
||||
response.sendError(_403_FORBIDDEN_);
|
||||
return;
|
||||
}
|
||||
|
||||
//1.响应成功
|
||||
response.setStatus(_101_SWITCHING_PROTOCOLS_);
|
||||
response.setHeader(_CONNECTION_, _UPGRADE_);
|
||||
response.setHeader(_UPGRADE_, _WEBSOCKET_);
|
||||
|
||||
//2.响应Sec-WebSocket-Accept&Sec-WebSocket-Protocol
|
||||
String key = request.getHeader(_SEC_WEBSOCKET_KEY_);
|
||||
String accept = Base64.encode(SHA1.encodeByte(key + _WEBSOCKET_SALT_, _UTF_8_C_));
|
||||
response.setHeader(_SEC_WEBSOCKET_ACCEPT_, accept);
|
||||
|
||||
String protocol = request.getHeader(_SEC_WEBSOCKET_PROTOCOL_, null);
|
||||
if (protocol != null)
|
||||
{//响应协议
|
||||
response.setHeader(_SEC_WEBSOCKET_PROTOCOL_, protocol);
|
||||
}
|
||||
|
||||
//3.升级连接为WS连接
|
||||
HttpConnection conn = ((HttpRequestAbs)request).getConnection();
|
||||
conn.doWebsocket(request.getContext(), protocol, session.getId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.zhiqim.kernel.annotation.AnAlias;
|
||||
import org.zhiqim.kernel.constants.HttpConstants;
|
||||
|
||||
/**
|
||||
* HTTPD常量定义
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
@AnAlias("HttpdConstants")
|
||||
public interface HttpdConstants extends HttpConstants
|
||||
{
|
||||
//浏览器相关参数
|
||||
public static final String _ZHTTPD_ = "zhiqim_httpd_v1.5.0";
|
||||
public static final String _TOKEN_ = "_token_";
|
||||
public static final String _MSIE_ = "msie";
|
||||
public static final String _MSTRIDENT_ = "trident";
|
||||
public static final String _FIREFOX_ = "firefox";
|
||||
public static final String _WEBKIT_ = "webkit";
|
||||
public static final String _CHROME_ = "chrome";
|
||||
public static final String _SAFARI_ = "safari";
|
||||
public static final String _MOBILE_ = "mobile";
|
||||
public static final String _WWW_ = "www";
|
||||
public static final String _MICROMESSAGER_ = "micromessenger";
|
||||
|
||||
//默认的HTTP环境和会话管理器
|
||||
public static final String _HTTP_CONTEXT_CLASS_ = "org.zhiqim.httpd.context.ZmlContext";
|
||||
public static final String _HTTP_SESSION_MANAGER_DEFAULT_ = "org.zhiqim.httpd.sessioner.HashSessionManager";
|
||||
public static final String _HTTP_SESSION_USER_ = "org.zhiqim.httpd.HttpSessionUser";
|
||||
public static final String _HTTP_SESSION_IP_ = "org.zhiqim.httpd.HttpSession.sessionIp";
|
||||
public static final String _HTTP_SESSION_UA_ = "org.zhiqim.httpd.HttpSession.userAgent";
|
||||
public static final String _HTTP_REQUEST_PARAM_MATCH_ = "org.zhiqim.httpd.HttpRequest.paramMatch";
|
||||
|
||||
//常用的SSL协议|算法和类型
|
||||
public static final String SSL_PROTOCOL = "TLS"; //协议
|
||||
public static final String SSL_ALGORITHM = "SunX509";//算法
|
||||
public static final String SSL_KEYSTORE_TYPE = "JKS"; //类型
|
||||
|
||||
//常用的三个文件放到包里
|
||||
public static final String _PATH_FAVICON_ICO_ = "/org/zhiqim/httpd/resources/favicon.ico";
|
||||
public static final String _PATH_CROSSDOMAIN_XML_ = "/org/zhiqim/httpd/resources/crossdomain.xml";
|
||||
public static final String _PATH_MIME_PROPERTIES_ = "/org/zhiqim/httpd/resources/mime.properties";
|
||||
|
||||
//默认提供的处理器
|
||||
public static final String _PATH_FAVICON_ = "/favicon.ico";
|
||||
public static final String _PATH_CROSSDOMAIN_ = "/crossdomain.xml";
|
||||
public static final String _PATH_SERVICE_WS_ = "/service/ws";
|
||||
|
||||
//上下文环境的常量
|
||||
public static final String _CONTEXT_ = "context";
|
||||
public static final String _SESSION_ = "session";
|
||||
public static final String _SESSION_ID_ = "sessionId";
|
||||
public static final String _SESSION_USER_ = "sessionUser";
|
||||
public static final String _SESSION_NAME_ = "sessionName";
|
||||
public static final String _REQUEST_ = "request";
|
||||
public static final String _RESPONSE_ = "response";
|
||||
public static final String _LOG_ = "log";
|
||||
public static final String _AIO_ = "AIO";
|
||||
public static final String _BIO_ = "BIO";
|
||||
public static final String _NIO_ = "NIO";
|
||||
public static final ByteBuffer _HELLO_N_ = ByteBuffer.wrap(_ZHTTPD_.getBytes());
|
||||
|
||||
//上下文环境的常量(知启蒙特有的定义)
|
||||
public static final String _ZHIQIM_CLIENT_TYPE_ = "zhiqimClientType";
|
||||
|
||||
//重定向支持的三个常量定义
|
||||
public static final String _REDIRECT_HISTORY_ = "-1"; //后退,调用window.history.back();
|
||||
public static final String _REDIRECT_CLOSE_WINDOW_ = "closeWindow";//关闭窗口,调用window.close();
|
||||
public static final String _REDIRECT_CLOSE_DIALOG_ = "closeDialog";//关闭对话框,调用parent.Z.Dialog.close();
|
||||
|
||||
//表单参数中两个重要标志
|
||||
public static final String _PARAM_CALL_FRAME_ = "zCallFrame";
|
||||
public static final String _PARAM_FORM_INDEX_ = "zFormIndex";
|
||||
public static final String _PARAM_DIALOG_FRAME_ = "zDialogFrame";
|
||||
|
||||
//HTTP协议长度定义
|
||||
public static final int _MAX_LINE_LEN_ = 8 * KiB;
|
||||
public static final int _MAX_HEADER_LINE_ = 128;
|
||||
public static final int _MAX_CONTENT_LEN_ = 8 * MiB;
|
||||
public static final int _MAX_CHUNKED_SIZE_ = MiB;
|
||||
public static final int _MAX_EXPIRES_ = 3600;
|
||||
|
||||
//标记连接处理进度
|
||||
public static final int _01_CREATE_ = 1; //连接被listner创建
|
||||
public static final int _02_PARSE_HEADER_ = 2; //解析请求头
|
||||
public static final int _03_CHECK_HEADER_ = 3; //检查请求头
|
||||
public static final int _04_QUERY_CONTEXT_ = 4; //查找Context
|
||||
public static final int _05_QUERY_HANDLER_ = 5; //查找Handler
|
||||
public static final int _06_PARSE_CONTENT_ = 6; //解析请求内容
|
||||
public static final int _07_HANDLER_BEGIN_ = 7; //请求被Handler处理开始
|
||||
public static final int _08_INTERCEPTOR_ = 8; //请求被Interceptor处理
|
||||
public static final int _09_ACTION_ = 9; //请求被Action处理
|
||||
public static final int _10_HANDLER_END_ = 10;//请求被Handler处理结束
|
||||
public static final int _11_COMMITTED_ = 11;//提交响应完成
|
||||
public static final int _12_FINISHED_ = 12;//结束请求处理
|
||||
|
||||
public static final String _01_STEP_DESC_ = "[创建]";
|
||||
public static final String _02_STEP_DESC_ = "[解析请求头]";
|
||||
public static final String _03_STEP_DESC_ = "[检查请求头]";
|
||||
public static final String _04_STEP_DESC_ = "[查找上下文环境]";
|
||||
public static final String _05_STEP_DESC_ = "[查找处理器]";
|
||||
public static final String _06_STEP_DESC_ = "[解析请求内容]";
|
||||
public static final String _07_STEP_DESC_ = "[处理开始]";
|
||||
public static final String _08_STEP_DESC_ = "[拦截器处理中]";
|
||||
public static final String _09_STEP_DESC_ = "[业务处理中]";
|
||||
public static final String _10_STEP_DESC_ = "[处理完成]";
|
||||
public static final String _11_STEP_DESC_ = "[正在提交]";
|
||||
public static final String _12_STEP_DESC_ = "[提交完成]";
|
||||
|
||||
//HTTP服务配置
|
||||
public static final String _SERVER_CONTEXT_ = "context";
|
||||
|
||||
//HTTP监听配置
|
||||
public static final String _LISTEN_SCHEME_ = "scheme";
|
||||
public static final String _LISTEN_PORT_ = "port";
|
||||
public static final String _LISTEN_IO_ = "io";
|
||||
public static final String _LISTEN_IP_ADDRESS_ = "ipAddress";
|
||||
public static final String _LISTEN_SO_ITMEOUT_ = "soTimeout";
|
||||
public static final String _LISTEN_SO_LINGER_ = "soLinger";
|
||||
public static final String _LISTEN_SO_RECV_BUF_ = "soRecvBuf";
|
||||
public static final String _LISTEN_SO_SEND_BUF_ = "soSendBuf";
|
||||
public static final String _LISTEN_SO_IDLE_TIME_ = "soIdleTime";
|
||||
public static final String _LISTEN_PO_MIN_SIZE_ = "poMinSize";
|
||||
public static final String _LISTEN_PO_MAX_SIZE_ = "poMaxSize";
|
||||
public static final String _LISTEN_PO_IDLE_TIME_ = "poIdleTime";
|
||||
public static final String _LISTEN_PO_QUEUE_SIZE_ = "poQueueSize";
|
||||
public static final String _LISTEN_ACCESS_LOG_ = "accessLog";
|
||||
|
||||
//HTTPS证书相关
|
||||
public static final String _KEY_STORE_PATH_ = "keystorePath";
|
||||
public static final String _KEY_STORE_PASS_ = "keystorePass";
|
||||
public static final String _TRUST_STORE_PATH_ = "truststorePath";
|
||||
public static final String _TRUST_STORE_PASS_ = "truststorePass";
|
||||
public static final String _CLIENT_AUTH_ = "clientAuth";
|
||||
|
||||
//HTTP Context配置
|
||||
public static final String _CONTEXT_DOMAIN_ = "domain";
|
||||
public static final String _CONTEXT_PATH_ = "path";
|
||||
public static final String _CONTEXT_CLASS_ = "class";
|
||||
public static final String _CONTEXT_RESOURCE_TYPE_ = "resourceType";
|
||||
public static final String _CONTEXT_RESOURCE_PATH_ = "resourcePath";
|
||||
public static final String _CONTEXT_WELCOME_URL_ = "welcomeUrl";
|
||||
public static final String _CONTEXT_NOT_FOUND_URL_ = "notFoundUrl";
|
||||
public static final String _CONTEXT_MAX_CONTENT_LEN_ = "maxContentLength";
|
||||
public static final String _CONTEXT_CHUNK_SIZE_ = "chunkSize";
|
||||
public static final String _CONTEXT_EXPIRES_ = "expires";
|
||||
public static final String _CONTEXT_FILTER_ = "filter";
|
||||
public static final String _CONTEXT_ENCODING_ = "encoding";
|
||||
public static final String _CONTEXT_ORM_ = "orm";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd.bio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import org.zhiqim.httpd.HttpConnection;
|
||||
import org.zhiqim.httpd.HttpContext;
|
||||
import org.zhiqim.httpd.HttpListener;
|
||||
import org.zhiqim.httpd.HttpdConstants;
|
||||
import org.zhiqim.kernel.util.Threads;
|
||||
|
||||
/**
|
||||
* HTTP连接信息类(连接即请求),包括输入输出流,实现Runnable,用于线程处理
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public final class HttpBioConnection implements HttpConnection, Runnable, HttpdConstants
|
||||
{
|
||||
private String connId;
|
||||
|
||||
private HttpListener listener;
|
||||
private Socket socket;
|
||||
private InetAddress remoteAddress;
|
||||
private InputStream input;
|
||||
private OutputStream output;
|
||||
|
||||
//依次找到1.HttpHeader,2.HttpServer,3.HttpContext
|
||||
private HttpBioHeader header;
|
||||
|
||||
//websocket
|
||||
private HttpBioWebsocketConnection websocket;
|
||||
|
||||
public HttpBioConnection(HttpListener listener, Socket socket, InputStream input, OutputStream output)
|
||||
{//HTTP
|
||||
this.connId = sequence.nextString();
|
||||
|
||||
this.listener = listener;
|
||||
this.socket = socket;
|
||||
this.remoteAddress = socket.getInetAddress();
|
||||
this.input = input;
|
||||
this.output = output;
|
||||
|
||||
this.header = new HttpBioHeader(this);
|
||||
}
|
||||
|
||||
public HttpBioConnection(HttpListener listener, Socket socket, InputStream input, OutputStream output, X509Certificate[] certs)
|
||||
{//HTTPS
|
||||
this(listener, socket, input, output);
|
||||
//用于业务再次认证
|
||||
this.header.setCertificates(certs);
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
//获取连接对应的websocket属性
|
||||
/***********************************************************************/
|
||||
|
||||
/** 是否是websocket连接 */
|
||||
public boolean isWebsocket()
|
||||
{
|
||||
return websocket != null;
|
||||
}
|
||||
|
||||
/** 关联Websocket */
|
||||
public void doWebsocket(HttpContext context, String protocol, String sessionId)
|
||||
{
|
||||
this.websocket = new HttpBioWebsocketConnection(this, context, protocol, sessionId);
|
||||
this.websocket.open();
|
||||
}
|
||||
|
||||
/** 是否活动 */
|
||||
public boolean isActive()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/** 是否超时 */
|
||||
public boolean isOvertime()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/** 是否已关闭 */
|
||||
public boolean isClosed()
|
||||
{
|
||||
return socket.isClosed();
|
||||
}
|
||||
|
||||
/********************************************************************************/
|
||||
//处理请求
|
||||
/********************************************************************************/
|
||||
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
header.execute();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/** 写入数据 */
|
||||
public void write(byte[] data) throws IOException
|
||||
{
|
||||
write(data, 0, data.length);
|
||||
}
|
||||
|
||||
/** 写入数据 */
|
||||
public void write(byte[] data, int off, int len) throws IOException
|
||||
{
|
||||
output.write(data, off, len);
|
||||
}
|
||||
|
||||
/** 关闭连接 */
|
||||
public void close()
|
||||
{//由sender回调
|
||||
listener.remove(this);
|
||||
|
||||
Threads.closeIgnoreException(input);
|
||||
Threads.closeIgnoreException(output);
|
||||
Threads.closeIgnoreException(socket);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************/
|
||||
//获取连接属性上的参数
|
||||
/***********************************************************************/
|
||||
|
||||
@Override
|
||||
public String getId()
|
||||
{
|
||||
return connId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpListener getListener()
|
||||
{
|
||||
return listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteAddr()
|
||||
{
|
||||
return remoteAddress.getHostAddress();
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
//请求属性
|
||||
/***************************************************************************/
|
||||
|
||||
public InputStream getInputStream()
|
||||
{
|
||||
return input;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd.bio;
|
||||
|
||||
import org.zhiqim.httpd.HttpHeaderAbs;
|
||||
import org.zhiqim.httpd.HttpInputStream;
|
||||
import org.zhiqim.httpd.HttpRequestAbs;
|
||||
import org.zhiqim.httpd.HttpSenderImpl;
|
||||
|
||||
/**
|
||||
* BIO请求头
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-2-27 新建与整理
|
||||
* @version v1.5.0 @author zouzhigang 2018-9-12 和NIO请求头抽象到HttpHeaderAbs中
|
||||
*/
|
||||
public class HttpBioHeader extends HttpHeaderAbs
|
||||
{
|
||||
/** 构造函数 */
|
||||
public HttpBioHeader (HttpBioConnection conn)
|
||||
{
|
||||
super(conn, new HttpInputStream(conn.getInputStream()), null);
|
||||
}
|
||||
|
||||
public HttpSenderImpl newSender()
|
||||
{
|
||||
return new HttpSenderImpl(this, true);
|
||||
}
|
||||
|
||||
public HttpRequestAbs newRequest()
|
||||
{
|
||||
return new HttpBioRequest(this);
|
||||
}
|
||||
|
||||
public boolean isBio()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd.bio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
|
||||
import org.zhiqim.httpd.HttpListener;
|
||||
import org.zhiqim.httpd.HttpServer;
|
||||
import org.zhiqim.kernel.util.Asserts;
|
||||
import org.zhiqim.kernel.util.Sockets;
|
||||
import org.zhiqim.kernel.util.Threads;
|
||||
import org.zhiqim.kernel.util.Validates;
|
||||
|
||||
/**
|
||||
* HTTP阻塞式监听器
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public class HttpBioListener extends HttpListener
|
||||
{
|
||||
private ServerSocket serverSocket;
|
||||
|
||||
public HttpBioListener(HttpServer server)
|
||||
{
|
||||
super(server);
|
||||
}
|
||||
|
||||
@Override /** 线程开启前 */
|
||||
protected boolean openBefore()
|
||||
{
|
||||
//监听参数和线程池
|
||||
super.openBefore();
|
||||
|
||||
try
|
||||
{//监听端口和守护线程
|
||||
if (Validates.isEmpty(listenerIp))
|
||||
serverSocket = new ServerSocket(listenerPort);
|
||||
else
|
||||
serverSocket = new ServerSocket(listenerPort, 50, InetAddress.getByName(listenerIp));
|
||||
serverSocket.setReuseAddress(true);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw Asserts.exception(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override /** 线程关闭后 */
|
||||
protected void closeAfter()
|
||||
{
|
||||
if (serverSocket != null)
|
||||
{//关闭监听
|
||||
Threads.closeIgnoreException(serverSocket);
|
||||
serverSocket = null;
|
||||
}
|
||||
|
||||
//关闭父类的控制器/定时任务/连接列表
|
||||
super.closeAfter();
|
||||
}
|
||||
|
||||
@Override /** 线程持续运行 */
|
||||
protected void loop()
|
||||
{
|
||||
try
|
||||
{
|
||||
Socket socket = serverSocket.accept();
|
||||
Sockets.setOption(socket, true, soTimeoutMs, soLingerS, false);
|
||||
|
||||
//连接交给控制器多线程处理
|
||||
controller.execute(add(newConnection(socket)));
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
if (!_SOCKET_CLOSED_.equalsIgnoreCase(e.getMessage()))
|
||||
{//非服务端自己关闭连接导致的异常打印
|
||||
log.error(toString() + "SocketException异常", e);
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
log.error(toString() + "IO异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
/** 新建连接 */
|
||||
private HttpBioConnection newConnection(Socket socket) throws IOException
|
||||
{
|
||||
return new HttpBioConnection(this, socket, socket.getInputStream(), socket.getOutputStream());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd.bio;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.zhiqim.httpd.HttpRequestAbs;
|
||||
import org.zhiqim.kernel.util.Streams;
|
||||
import org.zhiqim.kernel.util.Urls;
|
||||
import org.zhiqim.kernel.util.Zips;
|
||||
|
||||
/**
|
||||
* HTTP请求类
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public class HttpBioRequest extends HttpRequestAbs
|
||||
{
|
||||
/** 构造函数 */
|
||||
public HttpBioRequest (HttpBioHeader header)
|
||||
{
|
||||
super(header);
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
//解析请求头、内容、会话和证书等
|
||||
/***********************************************************************/
|
||||
|
||||
/**
|
||||
* 分析请求内容
|
||||
*
|
||||
* @exception IOException IO异常
|
||||
*/
|
||||
public boolean parseContent() throws IOException
|
||||
{
|
||||
//第十二步,解析内容流
|
||||
int cLen = getContentLength();
|
||||
if (cLen <= 0)
|
||||
{//无内容
|
||||
bis = new ByteArrayInputStream(new byte[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
//有内容
|
||||
byte[] contentBytes = Streams.getBytes(input, cLen);
|
||||
bis = new ByteArrayInputStream(contentBytes, 0, cLen);
|
||||
|
||||
if (isRequestGZip())
|
||||
bis = Zips.unGZip(bis);
|
||||
|
||||
if (_POST_.equals(header.getMethod()) && _APPLICATION_X_WWW_FORM_.equals(header.getMimeType()))
|
||||
{//form表单提交方式要解析到内容参数表中
|
||||
String line = new String(contentBytes, header.getCharacterEncoding());
|
||||
Urls.toMap(line, cntParamMap.instance(), header.getCharacterEncoding());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙,邂逅框架梦]
|
||||
*
|
||||
* 知启蒙WEB容器(zhiqim_httpd)在LGPL3.0协议下开源:https://www.zhiqim.com/gitcan/zhiqim/zhiqim_httpd.htm
|
||||
*
|
||||
* This file is part of [zhiqim_httpd].
|
||||
*
|
||||
* [zhiqim_httpd] is free software: you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* [zhiqim_httpd] is distributed in the hope that it will
|
||||
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with [zhiqim_httpd].
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.zhiqim.httpd.bio;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import javax.net.ssl.SSLServerSocket;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocket;
|
||||
|
||||
import org.zhiqim.httpd.HttpCertificate;
|
||||
import org.zhiqim.httpd.HttpListener;
|
||||
import org.zhiqim.httpd.HttpServer;
|
||||
import org.zhiqim.httpd.HttpSslConfig;
|
||||
import org.zhiqim.kernel.util.Asserts;
|
||||
import org.zhiqim.kernel.util.Hexs;
|
||||
import org.zhiqim.kernel.util.Sockets;
|
||||
import org.zhiqim.kernel.util.Threads;
|
||||
import org.zhiqim.kernel.util.Validates;
|
||||
import org.zhiqim.kernel.util.codes.SSL;
|
||||
|
||||
/**
|
||||
* HTTPS阻塞式监听器
|
||||
*
|
||||
* @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
|
||||
*/
|
||||
public class HttpBioSslListener extends HttpListener
|
||||
{
|
||||
private static final String SSL_SESSION_CACHE = HttpCertificate.class.getName();
|
||||
private static final String SSL_NULL_WITH_NULL_NULL = "SSL_NULL_WITH_NULL_NULL";
|
||||
|
||||
private final HttpSslConfig ssl;
|
||||
private SSLServerSocket serverSocket;
|
||||
|
||||
/** 构造函数 */
|
||||
public HttpBioSslListener(HttpServer server)
|
||||
{
|
||||
super(server);
|
||||
this.ssl = new HttpSslConfig();
|
||||
}
|
||||
|
||||
@Override /** 协议 */
|
||||
public String getScheme()
|
||||
{
|
||||
return _HTTPS_;
|
||||
}
|
||||
|
||||
@Override /** 线程启动前 */
|
||||
protected boolean openBefore()
|
||||
{
|
||||
try
|
||||
{
|
||||
//优先SSL参数(五项,其中Keystore两项必须)
|
||||
this.ssl.initParam(listenerGroup);
|
||||
|
||||
//监听参数和线程池
|
||||
super.openBefore();
|
||||
|
||||
//监听端口和守护线程
|
||||
SSLServerSocketFactory factory = ssl.createFactory();
|
||||
if (Validates.isEmpty(listenerIp))
|
||||
serverSocket = (SSLServerSocket)factory.createServerSocket(listenerPort);
|
||||
else
|
||||
serverSocket = (SSLServerSocket)factory.createServerSocket(listenerPort, 50, InetAddress.getByName(listenerIp));
|
||||
serverSocket.setReuseAddress(true);
|
||||
serverSocket.setNeedClientAuth(ssl.isClientAuth());
|
||||
serverSocket.setWantClientAuth(ssl.isClientAuth());
|
||||
return true;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
throw Asserts.exception(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override /** 线程关闭之后 */
|
||||
protected void closeAfter()
|
||||
{
|
||||
//1.关闭监听
|
||||
if (serverSocket != null)
|
||||
{
|
||||
Threads.closeIgnoreException(serverSocket);
|
||||
serverSocket = null;
|
||||
}
|
||||
|
||||
//2.关闭定时任务等父类定义
|
||||
super.closeAfter();
|
||||
|
||||
//3.打印退出日志
|
||||
log.info(toString() + "退出");
|
||||
}
|
||||
|
||||
@Override /** 线程持续运行 */
|
||||
protected void loop()
|
||||
{
|
||||
try
|
||||
{
|
||||
Socket socket = serverSocket.accept();
|
||||
Sockets.setOption(socket, true, soTimeoutMs, soLingerS, false);
|
||||
|
||||
SSLSocket sslSocket = (SSLSocket)socket;
|
||||
SSLSession sslSession = sslSocket.getSession();
|
||||
String cipherSuite = sslSession.getCipherSuite();
|
||||
if (cipherSuite == null || SSL_NULL_WITH_NULL_NULL.equals(cipherSuite))
|
||||
{//HTTP访问,未使用SSL
|
||||
socket.close();
|
||||
return;
|
||||
}
|
||||
|
||||
String sslSessionId = null;
|
||||
X509Certificate[] x509Certs = null;
|
||||
HttpCertificate sslSessionCache = (HttpCertificate)sslSession.getValue(SSL_SESSION_CACHE);
|
||||
if (sslSessionCache != null)
|
||||
{
|
||||
x509Certs = sslSessionCache.getCerts();
|
||||
sslSessionId = sslSessionCache.getSessionId();
|
||||
}
|
||||
else
|
||||
{
|
||||
x509Certs = SSL.getCertChain(sslSession);
|
||||
byte[] bytes = sslSession.getId();
|
||||
sslSessionId = Hexs.toHexString(bytes);
|
||||
sslSessionCache = new HttpCertificate(sslSessionId, x509Certs);
|
||||
sslSession.putValue(SSL_SESSION_CACHE, sslSessionCache);
|
||||
}
|
||||
|
||||
if (x509Certs == null && ssl.isClientAuth())
|
||||
{
|
||||
socket.close();
|
||||
return;
|
||||
}
|
||||
|
||||
//连接交给控制器多线程处理
|
||||
controller.execute(add(newConnection(socket, x509Certs)));
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
if (!_SOCKET_CLOSED_.equalsIgnoreCase(e.getMessage()))
|
||||
{//非服务端自己关闭连接导致的异常打印
|
||||
log.error(toString() + "SocketException异常", e);
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
log.error(toString() + "IO异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
/** 新建连接 */
|
||||
private HttpBioConnection newConnection(Socket socket, X509Certificate[] x509Certs) throws IOException
|
||||
{//把输入输出流的引用先拿出来
|
||||
return new HttpBioConnection(this, socket, socket.getInputStream(), socket.getOutputStream(), x509Certs);
|
||||
}
|
||||
}
|
||||
Sommige bestanden werden niet getoond omdat er teveel bestanden zijn veranderd in deze diff Meer weergeven
Verwijs in nieuw issue
Block a user